Merge "Add Codec2 AIDL interface"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index e58ae6a..8c32f14 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -91,12 +91,14 @@
name: "android.hardware.audio.core",
vendor_available: true,
srcs: [
+ "android/hardware/audio/core/AudioMode.aidl",
"android/hardware/audio/core/AudioPatch.aidl",
"android/hardware/audio/core/AudioRoute.aidl",
"android/hardware/audio/core/IConfig.aidl",
"android/hardware/audio/core/IModule.aidl",
"android/hardware/audio/core/IStreamIn.aidl",
"android/hardware/audio/core/IStreamOut.aidl",
+ "android/hardware/audio/core/ITelephony.aidl",
"android/hardware/audio/core/MmapBufferDescriptor.aidl",
"android/hardware/audio/core/ModuleDebug.aidl",
"android/hardware/audio/core/StreamDescriptor.aidl",
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl
similarity index 77%
copy from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
copy to audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl
index 5ff45f8..336f9b5 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/AudioMode.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -31,15 +31,12 @@
// 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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
- int versionNumber;
- @utf8InCpp String rpcAuthorName;
- int supportedEekCurve = 0;
- @nullable @utf8InCpp String uniqueId;
- const int CURVE_NONE = 0;
- const int CURVE_P256 = 1;
- const int CURVE_25519 = 2;
+package android.hardware.audio.core;
+@Backing(type="int") @VintfStability
+enum AudioMode {
+ NORMAL = 0,
+ RINGTONE = 1,
+ IN_CALL = 2,
+ IN_COMMUNICATION = 3,
+ CALL_SCREEN = 4,
}
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 a8bbb15..be382c5 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
@@ -35,6 +35,7 @@
@VintfStability
interface IModule {
void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
+ @nullable android.hardware.audio.core.ITelephony getTelephony();
android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
void disconnectExternalDevice(int portId);
android.hardware.audio.core.AudioPatch[] getAudioPatches();
@@ -49,6 +50,15 @@
boolean setAudioPortConfig(in android.media.audio.common.AudioPortConfig requested, out android.media.audio.common.AudioPortConfig suggested);
void resetAudioPatch(int patchId);
void resetAudioPortConfig(int portConfigId);
+ boolean getMasterMute();
+ void setMasterMute(boolean mute);
+ float getMasterVolume();
+ void setMasterVolume(float volume);
+ boolean getMicMute();
+ void setMicMute(boolean mute);
+ void updateAudioMode(android.hardware.audio.core.AudioMode mode);
+ void updateScreenRotation(android.hardware.audio.core.IModule.ScreenRotation rotation);
+ void updateScreenState(boolean isTurnedOn);
@VintfStability
parcelable OpenInputStreamArguments {
int portConfigId;
@@ -72,4 +82,11 @@
android.hardware.audio.core.IStreamOut stream;
android.hardware.audio.core.StreamDescriptor desc;
}
+ @Backing(type="int") @VintfStability
+ enum ScreenRotation {
+ DEG_0 = 0,
+ DEG_90 = 1,
+ DEG_180 = 2,
+ DEG_270 = 3,
+ }
}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
similarity index 77%
copy from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
copy to audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
index 5ff45f8..a8c58c1 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ITelephony.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -31,15 +31,9 @@
// 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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
- int versionNumber;
- @utf8InCpp String rpcAuthorName;
- int supportedEekCurve = 0;
- @nullable @utf8InCpp String uniqueId;
- const int CURVE_NONE = 0;
- const int CURVE_P256 = 1;
- const int CURVE_25519 = 2;
+package android.hardware.audio.core;
+@VintfStability
+interface ITelephony {
+ android.hardware.audio.core.AudioMode[] getSupportedAudioModes();
+ void switchAudioMode(android.hardware.audio.core.AudioMode mode);
}
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 db1ac22..3a77ad1 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
@@ -39,16 +39,31 @@
int frameSizeBytes;
long bufferSizeFrames;
android.hardware.audio.core.StreamDescriptor.AudioBuffer audio;
- const int COMMAND_BURST = 1;
+ const int LATENCY_UNKNOWN = -1;
@FixedSize @VintfStability
parcelable Position {
long frames;
long timeNs;
}
+ @Backing(type="int") @VintfStability
+ enum State {
+ STANDBY = 1,
+ IDLE = 2,
+ ACTIVE = 3,
+ PAUSED = 4,
+ DRAINING = 5,
+ DRAIN_PAUSED = 6,
+ ERROR = 100,
+ }
@FixedSize @VintfStability
- parcelable Command {
- int code;
- int fmqByteCount;
+ union Command {
+ int hal_reserved_exit;
+ android.media.audio.common.Void start;
+ int burst;
+ android.media.audio.common.Void drain;
+ android.media.audio.common.Void standby;
+ android.media.audio.common.Void pause;
+ android.media.audio.common.Void flush;
}
@FixedSize @VintfStability
parcelable Reply {
@@ -57,6 +72,8 @@
android.hardware.audio.core.StreamDescriptor.Position observable;
android.hardware.audio.core.StreamDescriptor.Position hardware;
int latencyMs;
+ int xrunFrames;
+ android.hardware.audio.core.StreamDescriptor.State state = android.hardware.audio.core.StreamDescriptor.State.STANDBY;
}
@VintfStability
union AudioBuffer {
diff --git a/audio/aidl/android/hardware/audio/core/AudioMode.aidl b/audio/aidl/android/hardware/audio/core/AudioMode.aidl
new file mode 100644
index 0000000..0943a55
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/AudioMode.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * The audio mode describes states of the audio system of the device that
+ * can significantly affect the rules of audio routing, volume control, etc.
+ * The audio mode is controlled by the framework, however the HAL has some
+ * flexibility in the choice of modes to support, see 'IModule.updateAudioMode'.
+ */
+@VintfStability
+@Backing(type="int")
+enum AudioMode {
+ /** No active calls. */
+ NORMAL = 0,
+ /** The device is playing the ringtone. */
+ RINGTONE = 1,
+ /** The call is handled by the telephony stack ("voice call"). */
+ IN_CALL = 2,
+ /** The call is handled by an application ("VoIP call"). */
+ IN_COMMUNICATION = 3,
+ /** Call screening is in progress. */
+ CALL_SCREEN = 4,
+}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index 735f87f..be40051 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -18,10 +18,12 @@
import android.hardware.audio.common.SinkMetadata;
import android.hardware.audio.common.SourceMetadata;
+import android.hardware.audio.core.AudioMode;
import android.hardware.audio.core.AudioPatch;
import android.hardware.audio.core.AudioRoute;
import android.hardware.audio.core.IStreamIn;
import android.hardware.audio.core.IStreamOut;
+import android.hardware.audio.core.ITelephony;
import android.hardware.audio.core.ModuleDebug;
import android.hardware.audio.core.StreamDescriptor;
import android.media.audio.common.AudioOffloadInfo;
@@ -60,6 +62,19 @@
void setModuleDebug(in ModuleDebug debug);
/**
+ * Retrieve the interface to control telephony audio.
+ *
+ * If the HAL module supports telephony functions, it must return an
+ * instance of the ITelephony interface. The same instance must be returned
+ * during the lifetime of the HAL module. If the HAL module does not support
+ * telephony, a null must be returned, without throwing any errors.
+ *
+ * @return An instance of the ITelephony interface implementation.
+ * @throws EX_ILLEGAL_STATE If there was an error creating an instance.
+ */
+ @nullable ITelephony getTelephony();
+
+ /**
* Set a device port of an external device into connected state.
*
* This method is used to inform the HAL module that an external device has
@@ -263,6 +278,9 @@
* be completing with an error, although data (zero filled) will still be
* provided.
*
+ * After the stream has been opened, it remains in the STANDBY state, see
+ * StreamDescriptor for more details.
+ *
* @return An opened input stream and the associated descriptor.
* @param args The pack of arguments, see 'OpenInputStreamArguments' parcelable.
* @throws EX_ILLEGAL_ARGUMENT In the following cases:
@@ -325,6 +343,9 @@
* StreamDescriptor will be completing with an error, although the data
* will still be accepted and immediately discarded.
*
+ * After the stream has been opened, it remains in the STANDBY state, see
+ * StreamDescriptor for more details.
+ *
* @return An opened output stream and the associated descriptor.
* @param args The pack of arguments, see 'OpenOutputStreamArguments' parcelable.
* @throws EX_ILLEGAL_ARGUMENT In the following cases:
@@ -481,4 +502,140 @@
* - If the port config is used by a patch.
*/
void resetAudioPortConfig(int portConfigId);
+
+ /**
+ * Get the current state of audio output muting.
+ *
+ * If the HAL module supports muting its combined output completely,
+ * this method returns whether muting is currently enabled.
+ *
+ * Note that muting operates independently from the master volume.
+ *
+ * @return Whether the output from the module is muted.
+ * @throws EX_UNSUPPORTED_OPERATION If muting of combined output
+ * is not supported by the module.
+ */
+ boolean getMasterMute();
+
+ /**
+ * Set the current value of the audio output muting.
+ *
+ * If the HAL module supports muting its combined output completely, this
+ * method controls the mute. Note that for modules supporting telephony,
+ * muting does not affect the voice call.
+ *
+ * For HAL modules not supporting this operation, it's functionality is
+ * typically emulated by the client, in the digital domain.
+ *
+ * @param mute Whether the output from the module is muted.
+ * @throws EX_UNSUPPORTED_OPERATION If muting of combined output
+ * is not supported by the module.
+ */
+ void setMasterMute(boolean mute);
+
+ /**
+ * Get the current value of the audio output attenuation.
+ *
+ * If the HAL module supports attenuating the level its combined output,
+ * this method returns the current attenuation value.
+ *
+ * @return Volume 1.0f means no attenuation (unity), 0.0f is mute.
+ * @throws EX_UNSUPPORTED_OPERATION If attenuation of combined output
+ * is not supported by the module.
+ */
+ float getMasterVolume();
+
+ /**
+ * Set the current value of the audio output attenuation.
+ *
+ * If the HAL module supports attenuating the level its combined output,
+ * this method sets the attenuation value. Note that for modules supporting
+ * telephony, the attenuation of the voice call volume is set separately
+ * via ITelephony interface.
+ *
+ * For HAL modules not supporting this operation, it's functionality is
+ * typically emulated by the client, in the digital domain.
+ *
+ * @param volume The new value, 1.0f means no attenuation (unity), 0.0f is mute.
+ * @throws EX_ILLEGAL_ARGUMENT If the value of the volume is outside of
+ * accepted range.
+ * @throws EX_UNSUPPORTED_OPERATION If attenuation of combined output
+ * is not supported by the module.
+ */
+ void setMasterVolume(float volume);
+
+ /**
+ * Get the current state of audio input muting.
+ *
+ * If the HAL module supports muting its external input, this method returns
+ * whether muting is currently enabled.
+ *
+ * @return Whether the input is muted.
+ * @throws EX_UNSUPPORTED_OPERATION If muting of input is not supported by
+ * the module.
+ */
+ boolean getMicMute();
+
+ /**
+ * Set the current value of the audio input muting.
+ *
+ * If the HAL module supports muting its external input, this method
+ * controls the mute.
+ *
+ * For HAL modules not supporting this operation, it's functionality is
+ * emulated by the client.
+ *
+ * @param mute Whether input is muted.
+ * @throws EX_UNSUPPORTED_OPERATION If muting of input is not supported by
+ * the module.
+ */
+ void setMicMute(boolean mute);
+
+ /**
+ * 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
+ * informative notification sent to all modules, no reply is needed. The HAL
+ * module should silently ignore this notification if it does not need to
+ * be aware of the current audio mode.
+ *
+ * The client sends this notification to all HAL modules after successfully
+ * switching the telephony module by calling the 'ITelephony.switchAudioMode'
+ * method.
+ *
+ * @param mode The current mode.
+ */
+ void updateAudioMode(AudioMode mode);
+
+ @VintfStability
+ @Backing(type="int")
+ enum ScreenRotation {
+ /** Natural orientation. */
+ DEG_0 = 0,
+ DEG_90 = 1,
+ /** Upside down. */
+ DEG_180 = 2,
+ DEG_270 = 3,
+ }
+ /**
+ * Notify the HAL module on the change of the screen rotation.
+ *
+ * Informs the HAL of the current orientation of the device screen. This
+ * information can be used to optimize the output of built-in speakers.
+ * This is an informative notification sent to all modules, no reply is
+ * needed.
+ *
+ * @param rotation The current rotation.
+ */
+ void updateScreenRotation(ScreenRotation rotation);
+
+ /**
+ * Notify the HAL module on the change of the screen state.
+ *
+ * Informs the HAL whether the screen of the device is turned on. This is an
+ * informative notification sent to all modules, no reply is needed.
+ *
+ * @param isTurnedOn True if the screen is turned on.
+ */
+ void updateScreenState(boolean isTurnedOn);
}
diff --git a/audio/aidl/android/hardware/audio/core/ITelephony.aidl b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
new file mode 100644
index 0000000..a872c7c
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/ITelephony.aidl
@@ -0,0 +1,56 @@
+/*
+ * 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.hardware.audio.core.AudioMode;
+
+/**
+ * An instance of ITelephony manages settings which are specific to voice calls
+ * and SMS messaging functionality. This interface is optional to implement and
+ * provide by the vendor. It needs to be provided only if the device actually
+ * supports telephony.
+ */
+@VintfStability
+interface ITelephony {
+ /**
+ * Return the list of supported audio modes.
+ *
+ * The first 4 AudioModes: NORMAL, RINGTONE, IN_CALL, IN_COMMUNICATION must
+ * be supported by all implementations.
+ *
+ * This method is only called once, during the audio system initialization,
+ * and must return the same result all the time.
+ *
+ * @return The list of supported audio modes.
+ */
+ AudioMode[] getSupportedAudioModes();
+
+ /**
+ * Switch the HAL into a new audio mode.
+ *
+ * The current audio mode is always controlled by the client. The HAL must
+ * accept all modes returned by 'getSupportedAudioModes' and reject the
+ * rest. The HAL must return from this method only after switching itself
+ * to the specified mode, or throw an error if there was a problem during
+ * switching.
+ *
+ * @param mode The mode to switch to.
+ * @throws EX_UNSUPPORTED_OPERATION If the HAL does not support the specified mode.
+ * @throws EX_ILLEGAL_STATE If there was an error during switching.
+ */
+ void switchAudioMode(AudioMode mode);
+}
diff --git a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
index 2b1ed8c..2b1fc99 100644
--- a/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/android/hardware/audio/core/StreamDescriptor.aidl
@@ -19,6 +19,7 @@
import android.hardware.audio.core.MmapBufferDescriptor;
import android.hardware.common.fmq.MQDescriptor;
import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.media.audio.common.Void;
/**
* Stream descriptor contains fast message queues and buffers used for sending
@@ -33,6 +34,72 @@
* internal components of the stream while serving commands invoked via the
* stream's AIDL interface and commands invoked via the command queue of the
* descriptor.
+ *
+ * There is a state machine defined for the stream, which executes on the
+ * thread handling the commands from the queue. The states are defined based
+ * on the model of idealized producer and consumer connected via a ring buffer.
+ * For input streams, the "producer" is hardware, the "consumer" is software,
+ * for outputs streams it's the opposite. When the producer is active, but
+ * the buffer is full, the following actions are possible:
+ * - if the consumer is active, the producer blocks until there is space,
+ * this behavior is only possible for software producers;
+ * - if the consumer is passive:
+ * - the producer can preserve the buffer contents—a s/w producer can
+ * keep the data on their side, while a h/w producer can only drop captured
+ * data in this case;
+ * - or the producer overwrites old data in the buffer.
+ * Similarly, when an active consumer faces an empty buffer, it can:
+ * - block until there is data (producer must be active), only possible
+ * for software consumers;
+ * - walk away with no data; when the consumer is hardware, it must emit
+ * silence in this case.
+ *
+ * The model is defined below, note the asymmetry regarding the 'IDLE' state
+ * between input and output streams:
+ *
+ * Producer | Buffer state | Consumer | Applies | State
+ * active? | | active? | to |
+ * ==========|==============|==========|=========|==============================
+ * No | Empty | No | Both | STANDBY
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Filling up | No | Input | IDLE, overwrite behavior
+ * ----------|--------------|----------|---------|-----------------------------
+ * No | Empty | Yes† | Output | IDLE, h/w emits silence
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Not empty | Yes | Both | ACTIVE, s/w x-runs counted
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Filling up | No | Input | PAUSED, drop behavior
+ * ----------|--------------|----------|---------|-----------------------------
+ * Yes | Filling up | No† | Output | PAUSED, s/w stops writing once
+ * | | | | the buffer is filled up;
+ * | | | | h/w emits silence.
+ * ----------|--------------|----------|---------|-----------------------------
+ * No | Not empty | Yes | Both | DRAINING
+ * ----------|--------------|----------|---------|-----------------------------
+ * No | Not empty | No† | Output | DRAIN_PAUSED,
+ * | | | | h/w emits silence.
+ *
+ * † - note that for output, "buffer empty, h/w consuming" has the same outcome
+ * as "buffer not empty, h/w not consuming", but logically these conditions
+ * are different.
+ *
+ * State machines of both input and output streams start from the 'STANDBY'
+ * 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.
+ *
+ * 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
+ * commands (from the enum 'CommandCode') trigger state changes. The full list
+ * of states and commands is defined by constants of the 'State' enum. Note that
+ * the 'CLOSED' state does not have a constant in the interface because the
+ * 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.
*/
@JavaDerive(equals=true, toString=true)
@VintfStability
@@ -55,30 +122,97 @@
long timeNs;
}
- /**
- * The command used for audio I/O, see 'AudioBuffer'. For MMap No IRQ mode
- * this command only provides updated positions and latency because actual
- * audio I/O is done via the 'AudioBuffer.mmap' shared buffer.
- */
- const int COMMAND_BURST = 1;
+ @VintfStability
+ @Backing(type="int")
+ enum State {
+ /**
+ * 'STANDBY' is the initial state of the stream, entered after
+ * opening. Since both the producer and the consumer are inactive in
+ * this state, it allows the HAL module to put associated hardware into
+ * "standby" mode to save power.
+ */
+ STANDBY = 1,
+ /**
+ * In the 'IDLE' state the audio hardware is active. For input streams,
+ * the hardware is filling buffer with captured data, overwriting old
+ * contents on buffer wraparounds. For output streams, the buffer is
+ * still empty, and the hardware is outputting zeroes. The HAL module
+ * must not account for any under- or overruns as the client is not
+ * expected to perform audio I/O.
+ */
+ IDLE = 2,
+ /**
+ * The active state of the stream in which it handles audio I/O. The HAL
+ * module can assume that the audio I/O will be periodic, thus inability
+ * of the client to provide or consume audio data on time must be
+ * considered as an under- or overrun and indicated via the 'xrunFrames'
+ * field of the reply.
+ */
+ ACTIVE = 3,
+ /**
+ * In the 'PAUSED' state the consumer is inactive. For input streams,
+ * the hardware stops updating the buffer as soon as it fills up (this
+ * is the difference from the 'IDLE' state). For output streams,
+ * "inactivity" of hardware means that it does not consume audio data,
+ * but rather emits silence.
+ */
+ PAUSED = 4,
+ /**
+ * In the 'DRAINING' state the producer is inactive, the consumer is
+ * finishing up on the buffer contents, emptying it up. As soon as it
+ * gets empty, the stream transfers itself into the next state.
+ */
+ DRAINING = 5,
+ /**
+ * 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
+ * into the regular 'PAUSED' state.
+ */
+ DRAIN_PAUSED = 6,
+ /**
+ * 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.
+ */
+ ERROR = 100,
+ }
/**
* 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
* command.
+ *
+ * Variants of type 'Void' correspond to commands without
+ * arguments. Variants of other types correspond to commands with an
+ * argument. Would in future a need for a command with multiple argument
+ * arise, a Parcelable type should be used for the corresponding variant.
*/
@VintfStability
@FixedSize
- parcelable Command {
+ union Command {
/**
- * One of COMMAND_* codes.
+ * Reserved for the HAL implementation to allow unblocking the wait on a
+ * command and exiting the I/O thread. A command of this variant must
+ * never be sent from the client side. To prevent that, the
+ * implementation must pass a random cookie as the command argument,
+ * which is only known to the implementation.
*/
- int code;
+ int hal_reserved_exit;
/**
- * For output streams: the amount of bytes that the client requests the
- * HAL module to read from the 'audio.fmq' queue.
- * For input streams: the amount of bytes requested by the client to
- * read from the hardware into the 'audio.fmq' queue.
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void start;
+ /**
+ * The 'burst' command used for audio I/O, see 'AudioBuffer'. The value
+ * specifies:
+ *
+ * - for output streams: the amount of bytes that the client requests the
+ * HAL module to use out of the data contained in the 'audio.fmq' queue.
+ *
+ * - for input streams: the amount of bytes requested by the client to
+ * 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
@@ -90,12 +224,54 @@
* 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:
+ *
+ * - this command only provides updated positions and latency because
+ * actual audio I/O is done via the 'AudioBuffer.mmap' shared buffer.
+ * The client does not synchronize reads and writes into the buffer
+ * with sending of this command.
+ *
+ * - the value must always be set to 0.
*/
- int fmqByteCount;
+ int burst;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void drain;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ *
+ * Note that it's left on the discretion of the HAL implementation to
+ * assess all the necessary conditions that could prevent hardware from
+ * being suspended. Even if it can not be suspended, the state machine
+ * must still enter the 'STANDBY' state for consistency. Since the
+ * buffer must remain empty in this state, even if capturing hardware is
+ * still active, captured data must be discarded.
+ */
+ Void standby;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void pause;
+ /**
+ * See the state machines on the applicability of this command to
+ * different states.
+ */
+ Void flush;
}
MQDescriptor<Command, SynchronizedReadWrite> command;
/**
+ * The value used for the 'Reply.latencyMs' field when the effective
+ * latency can not be reported by the HAL module.
+ */
+ const int LATENCY_UNKNOWN = -1;
+
+ /**
* Used for providing replies to commands. The HAL module writes into
* the queue, the client reads. The queue can only contain a single reply,
* corresponding to the last command sent by the client.
@@ -107,29 +283,42 @@
* One of Binder STATUS_* statuses:
* - STATUS_OK: the command has completed successfully;
* - STATUS_BAD_VALUE: invalid value in the 'Command' structure;
- * - STATUS_INVALID_OPERATION: the mix port is not connected
- * to any producer or consumer, thus
- * positions can not be reported;
+ * - 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;
- *
*/
int status;
/**
- * For output streams: the amount of bytes actually consumed by the HAL
- * module from the 'audio.fmq' queue.
+ * Used with the 'burst' command only.
+ *
+ * For output streams: the amount of bytes of data actually consumed
+ * by the HAL module.
* For input streams: the amount of bytes actually provided by the HAL
* in the 'audio.fmq' queue.
*
- * The returned value must not exceed the value passed in the
- * 'fmqByteCount' field of the corresponding command or be negative.
+ * The returned value must not exceed the value passed as the
+ * argument of the corresponding command, or be negative.
*/
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'.
+ *
* For output streams: the moment when the specified stream position
* was presented to an external observer (i.e. presentation position).
* For input streams: the moment when data at the specified stream position
* was acquired (i.e. capture position).
+ *
+ * The observable position must never be reset by the HAL module.
+ * The data type of the frame counter is large enough to support
+ * continuous counting for years of operation.
*/
Position observable;
/**
@@ -138,9 +327,22 @@
*/
Position hardware;
/**
- * Current latency reported by the hardware.
+ * Current latency reported by the hardware. It is recommended to
+ * report the current latency for any command. If the value of latency
+ * can not be determined, this field must be set to 'LATENCY_UNKNOWN'.
*/
int latencyMs;
+ /**
+ * Number of frames lost due to an underrun (for input streams),
+ * or not provided on time (for output streams) for the **previous**
+ * transfer operation.
+ */
+ int xrunFrames;
+ /**
+ * The state that the stream was in while the HAL module was sending the
+ * reply.
+ */
+ State state = State.STANDBY;
}
MQDescriptor<Reply, SynchronizedReadWrite> reply;
@@ -170,42 +372,59 @@
@VintfStability
union AudioBuffer {
/**
- * The fast message queue used for all modes except MMap No IRQ. Both
- * reads and writes into this queue are non-blocking because access to
- * this queue is synchronized via the 'command' and 'reply' queues as
- * described below. The queue nevertheless uses 'SynchronizedReadWrite'
- * because there is only one reader, and the reading position must be
- * shared.
+ * The fast message queue used for BURST commands in all modes except
+ * MMap No IRQ. Both reads and writes into this queue are non-blocking
+ * because access to this queue is synchronized via the 'command' and
+ * 'reply' queues as described below. The queue nevertheless uses
+ * 'SynchronizedReadWrite' because there is only one reader, and the
+ * reading position must be shared.
+ *
+ * Note that the fast message queue is a transient buffer, only used for
+ * data transfer. Neither of the sides can use it to store any data
+ * outside of the 'BURST' operation. The consumer must always retrieve
+ * all data available in the fast message queue, even if it can not use
+ * it. The producer must re-send any unconsumed data on the next
+ * transfer operation. This restriction is posed in order to make the
+ * fast message queue fully transparent from the latency perspective.
*
* For output streams the following sequence of operations is used:
* 1. The client writes audio data into the 'audio.fmq' queue.
- * 2. The client writes the 'BURST' command into the 'command' queue,
+ * 2. The client writes the BURST command into the 'command' queue,
* and hangs on waiting on a read from the 'reply' queue.
* 3. The high priority thread in the HAL module wakes up due to 2.
- * 4. The HAL module reads the command and audio data.
+ * 4. The HAL module reads the command and audio data. According
+ * to the statement above, the HAL module must always read
+ * from the FMQ all the data it contains. The amount of data that
+ * the HAL module has actually consumed is indicated to the client
+ * via the 'reply.fmqByteCount' field.
* 5. The HAL module writes the command status and current positions
* 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.
*
* For input streams the following sequence of operations is used:
- * 1. The client writes the 'BURST' command into the 'command' queue,
+ * 1. The client writes the BURST command into the 'command' queue,
* and hangs on waiting on a read from the 'reply' queue.
* 2. The high priority thread in the HAL module wakes up due to 1.
* 3. The HAL module writes audio data into the 'audio.fmq' queue.
+ * The value of 'reply.fmqByteCount' must be the equal to the amount
+ * of data in the queue.
* 4. The HAL module writes the command status and current positions
* into 'reply' queue, and hangs on waiting on a read from
* the 'command' queue.
* 5. The client wakes up due to 4.
- * 6. The client reads the reply and audio data.
+ * 6. The client reads the reply and audio data. The client must
+ * always read from the FMQ all the data it contains.
+ *
*/
MQDescriptor<byte, SynchronizedReadWrite> fmq;
/**
* MMap buffers are shared directly with the DSP, which operates
- * independently from the CPU. Writes and reads into these buffers
- * are not synchronized with 'command' and 'reply' queues. However,
- * the client still uses the 'BURST' command for obtaining current
- * positions from the HAL module.
+ * independently from the CPU. Writes and reads into these buffers are
+ * not synchronized with 'command' and 'reply' queues. However, the
+ * client still uses the same commands for controlling the audio data
+ * exchange and for obtaining current positions and latency from the HAL
+ * module.
*/
MmapBufferDescriptor mmap;
}
diff --git a/audio/aidl/android/hardware/audio/core/stream-in-sm.gv b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
new file mode 100644
index 0000000..805dc32
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-in-sm.gv
@@ -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.
+
+// To render: dot -Tpng stream-in-sm.gv -o stream-in-sm.png
+digraph stream_in_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];
+ I -> STANDBY;
+ STANDBY -> IDLE [label="start"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // producer -> passive, buffer is cleared
+ IDLE -> ACTIVE [label="burst"]; // consumer -> active
+ ACTIVE -> ACTIVE [label="burst"];
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ PAUSED -> ACTIVE [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="<hardware failure>"];
+ ACTIVE -> ERROR [label="<hardware failure>"];
+ PAUSED -> ERROR [label="<hardware failure>"];
+ ANY_STATE -> CLOSED [label="→IStream*.close"];
+ CLOSED -> F;
+}
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
new file mode 100644
index 0000000..6aa5c61
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
@@ -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.
+
+// To render: dot -Tpng stream-out-sm.gv -o stream-out-sm.png
+digraph stream_out_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];
+ I -> STANDBY;
+ STANDBY -> IDLE [label="start"]; // consumer -> active
+ STANDBY -> PAUSED [label="burst"]; // producer -> active
+ IDLE -> STANDBY [label="standby"]; // consumer -> passive
+ IDLE -> ACTIVE [label="burst"]; // producer -> active
+ ACTIVE -> ACTIVE [label="burst"];
+ ACTIVE -> PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ PAUSED -> PAUSED [label="burst"];
+ PAUSED -> ACTIVE [label="start"]; // consumer -> active
+ PAUSED -> IDLE [label="flush"]; // producer -> passive, buffer is cleared
+ DRAINING -> IDLE [label="<empty buffer>"];
+ DRAINING -> ACTIVE [label="burst"]; // producer -> active
+ DRAINING -> DRAIN_PAUSED [label="pause"]; // consumer -> passive (not consuming)
+ DRAIN_PAUSED -> DRAINING [label="start"]; // consumer -> active
+ DRAIN_PAUSED -> PAUSED [label="burst"]; // producer -> active
+ DRAIN_PAUSED -> IDLE [label="flush"]; // buffer is cleared
+ IDLE -> ERROR [label="<hardware failure>"];
+ ACTIVE -> ERROR [label="<hardware failure>"];
+ DRAINING -> ERROR [label="<hardware failure>"];
+ ANY_STATE -> CLOSED [label="→IStream*.close"];
+ CLOSED -> F;
+}
diff --git a/audio/aidl/common/StreamWorker.cpp b/audio/aidl/common/StreamWorker.cpp
index 9bca760..dda0e4a 100644
--- a/audio/aidl/common/StreamWorker.cpp
+++ b/audio/aidl/common/StreamWorker.cpp
@@ -44,6 +44,10 @@
mWorkerStateChangeRequest = true;
}
}
+ join();
+}
+
+void ThreadController::join() {
if (mWorker.joinable()) {
mWorker.join();
}
diff --git a/audio/aidl/common/include/StreamWorker.h b/audio/aidl/common/include/StreamWorker.h
index 6260eca..ab2ec26 100644
--- a/audio/aidl/common/include/StreamWorker.h
+++ b/audio/aidl/common/include/StreamWorker.h
@@ -39,6 +39,9 @@
~ThreadController() { stop(); }
bool start(const std::string& name, int priority);
+ // Note: 'pause' and 'resume' methods should only be used on the "driving" side.
+ // In the case of audio HAL I/O, the driving side is the client, because the HAL
+ // implementation always blocks on getting a command.
void pause() { switchWorkerStateSync(WorkerState::RUNNING, WorkerState::PAUSE_REQUESTED); }
void resume() { switchWorkerStateSync(WorkerState::PAUSED, WorkerState::RESUME_REQUESTED); }
bool hasError() {
@@ -50,6 +53,10 @@
return mError;
}
void stop();
+ // Direct use of 'join' assumes that the StreamLogic is not intended
+ // to run forever, and is guaranteed to exit by itself. This normally
+ // only happen in tests.
+ void join();
bool waitForAtLeastOneCycle();
// Only used by unit tests.
@@ -133,7 +140,8 @@
void resume() { mThread.resume(); }
bool hasError() { return mThread.hasError(); }
std::string getError() { return mThread.getError(); }
- void stop() { return mThread.stop(); }
+ void stop() { mThread.stop(); }
+ void join() { mThread.join(); }
bool waitForAtLeastOneCycle() { return mThread.waitForAtLeastOneCycle(); }
// Only used by unit tests.
diff --git a/audio/aidl/common/tests/streamworker_tests.cpp b/audio/aidl/common/tests/streamworker_tests.cpp
index e3e484d..8ea8424 100644
--- a/audio/aidl/common/tests/streamworker_tests.cpp
+++ b/audio/aidl/common/tests/streamworker_tests.cpp
@@ -160,6 +160,14 @@
EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
}
+TEST_P(StreamWorkerTest, WorkerJoin) {
+ ASSERT_TRUE(worker.start());
+ stream.setStopStatus();
+ worker.join();
+ EXPECT_FALSE(worker.hasError());
+ EXPECT_TRUE(worker.hasNoWorkerCycleCalled(kWorkerIdleCheckTime));
+}
+
TEST_P(StreamWorkerTest, WorkerError) {
ASSERT_TRUE(worker.start());
stream.setErrorStatus();
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index d34d68c..0a92e99 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -39,6 +39,7 @@
"Configuration.cpp",
"Module.cpp",
"Stream.cpp",
+ "Telephony.cpp",
],
visibility: [
":__subpackages__",
@@ -81,6 +82,7 @@
],
header_libs: [
"libaudioaidl_headers",
+ "libaudio_system_headers",
"libsystem_headers",
],
cflags: [
@@ -107,18 +109,21 @@
defaults: ["aidlaudioeffectservice_defaults"],
shared_libs: [
"libbassboostsw",
+ "libbundleaidl",
"libdynamicsprocessingsw",
"libequalizersw",
"libhapticgeneratorsw",
"libloudnessenhancersw",
"libreverbsw",
+ "libtinyxml2",
"libvirtualizersw",
"libvisualizersw",
"libvolumesw",
],
srcs: [
- "EffectMain.cpp",
+ "EffectConfig.cpp",
"EffectFactory.cpp",
+ "EffectMain.cpp",
],
}
diff --git a/audio/aidl/default/EffectConfig.cpp b/audio/aidl/default/EffectConfig.cpp
new file mode 100644
index 0000000..e1427ec
--- /dev/null
+++ b/audio/aidl/default/EffectConfig.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "AHAL_EffectConfig"
+#include <android-base/logging.h>
+
+#include "effectFactory-impl/EffectConfig.h"
+
+using aidl::android::media::audio::common::AudioUuid;
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectConfig::EffectConfig(const std::string& file) {
+ tinyxml2::XMLDocument doc;
+ doc.LoadFile(file.c_str());
+ LOG(DEBUG) << __func__ << " loading " << file;
+ // parse the xml file into maps
+ if (doc.Error()) {
+ LOG(ERROR) << __func__ << " tinyxml2 failed to load " << file
+ << " error: " << doc.ErrorStr();
+ return;
+ }
+
+ auto registerFailure = [&](bool result) { mSkippedElements += result ? 0 : 1; };
+
+ for (auto& xmlConfig : getChildren(doc, "audio_effects_conf")) {
+ // Parse library
+ for (auto& xmlLibraries : getChildren(xmlConfig, "libraries")) {
+ for (auto& xmlLibrary : getChildren(xmlLibraries, "library")) {
+ registerFailure(parseLibrary(xmlLibrary));
+ }
+ }
+
+ // Parse effects
+ for (auto& xmlEffects : getChildren(xmlConfig, "effects")) {
+ for (auto& xmlEffect : getChildren(xmlEffects)) {
+ registerFailure(parseEffect(xmlEffect));
+ }
+ }
+
+ // Parse pre processing chains
+ for (auto& xmlPreprocess : getChildren(xmlConfig, "preprocess")) {
+ for (auto& xmlStream : getChildren(xmlPreprocess, "stream")) {
+ registerFailure(parseStream(xmlStream));
+ }
+ }
+
+ // Parse post processing chains
+ for (auto& xmlPostprocess : getChildren(xmlConfig, "postprocess")) {
+ for (auto& xmlStream : getChildren(xmlPostprocess, "stream")) {
+ registerFailure(parseStream(xmlStream));
+ }
+ }
+ }
+ LOG(DEBUG) << __func__ << " successfully parsed " << file << ", skipping " << mSkippedElements
+ << " element(s)";
+}
+
+std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> EffectConfig::getChildren(
+ const tinyxml2::XMLNode& node, const char* childTag) {
+ std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> children;
+ for (auto* child = node.FirstChildElement(childTag); child != nullptr;
+ child = child->NextSiblingElement(childTag)) {
+ children.emplace_back(*child);
+ }
+ return children;
+}
+
+bool EffectConfig::parseLibrary(const tinyxml2::XMLElement& xml) {
+ const char* name = xml.Attribute("name");
+ RETURN_VALUE_IF(!name, false, "noNameAttribute");
+ const char* path = xml.Attribute("path");
+ RETURN_VALUE_IF(!path, false, "noPathAttribute");
+
+ mLibraryMap[name] = path;
+ LOG(DEBUG) << __func__ << " " << name << " : " << path;
+ return true;
+}
+
+bool EffectConfig::parseEffect(const tinyxml2::XMLElement& xml) {
+ struct EffectLibraries effectLibraries;
+ std::vector<LibraryUuid> libraryUuids;
+ std::string name = xml.Attribute("name");
+ RETURN_VALUE_IF(name == "", false, "effectsNoName");
+
+ LOG(DEBUG) << __func__ << dump(xml);
+ struct LibraryUuid libraryUuid;
+ if (std::strcmp(xml.Name(), "effectProxy") == 0) {
+ // proxy lib and uuid
+ RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid, true), false, "parseProxyLibFailed");
+ effectLibraries.proxyLibrary = libraryUuid;
+ // proxy effect libs and UUID
+ auto xmlProxyLib = xml.FirstChildElement();
+ RETURN_VALUE_IF(!xmlProxyLib, false, "noLibForProxy");
+ while (xmlProxyLib) {
+ struct LibraryUuid tempLibraryUuid;
+ RETURN_VALUE_IF(!parseLibraryUuid(*xmlProxyLib, tempLibraryUuid), false,
+ "parseEffectLibFailed");
+ libraryUuids.push_back(std::move(tempLibraryUuid));
+ xmlProxyLib = xmlProxyLib->NextSiblingElement();
+ }
+ } else {
+ // expect only one library if not proxy
+ RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid), false, "parseEffectLibFailed");
+ libraryUuids.push_back(std::move(libraryUuid));
+ }
+
+ effectLibraries.libraries = std::move(libraryUuids);
+ mEffectsMap[name] = std::move(effectLibraries);
+ return true;
+}
+
+bool EffectConfig::parseStream(const tinyxml2::XMLElement& xml) {
+ LOG(DEBUG) << __func__ << dump(xml);
+ const char* type = xml.Attribute("type");
+ RETURN_VALUE_IF(!type, false, "noTypeInProcess");
+ RETURN_VALUE_IF(0 != mProcessingMap.count(type), false, "duplicateType");
+
+ for (auto& apply : getChildren(xml, "apply")) {
+ const char* name = apply.get().Attribute("effect");
+ RETURN_VALUE_IF(!name, false, "noEffectAttribute");
+ mProcessingMap[type].push_back(name);
+ LOG(DEBUG) << __func__ << " " << type << " : " << name;
+ }
+ return true;
+}
+
+bool EffectConfig::parseLibraryUuid(const tinyxml2::XMLElement& xml,
+ struct LibraryUuid& libraryUuid, bool isProxy) {
+ // Retrieve library name only if not effectProxy element
+ if (!isProxy) {
+ const char* name = xml.Attribute("library");
+ RETURN_VALUE_IF(!name, false, "noLibraryAttribute");
+ libraryUuid.name = name;
+ }
+
+ const char* uuid = xml.Attribute("uuid");
+ RETURN_VALUE_IF(!uuid, false, "noUuidAttribute");
+ RETURN_VALUE_IF(!stringToUuid(uuid, &libraryUuid.uuid), false, "invalidUuidAttribute");
+
+ LOG(DEBUG) << __func__ << (isProxy ? " proxy " : libraryUuid.name) << " : "
+ << libraryUuid.uuid.toString();
+ return true;
+}
+
+const char* EffectConfig::dump(const tinyxml2::XMLElement& element,
+ tinyxml2::XMLPrinter&& printer) const {
+ element.Accept(&printer);
+ return printer.CStr();
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index e03dda3..820b447 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "AHAL_EffectFactory"
#include <android-base/logging.h>
#include <dlfcn.h>
+#include <unordered_set>
#include "effect-impl/EffectTypes.h"
#include "effect-impl/EffectUUID.h"
@@ -26,22 +27,9 @@
namespace aidl::android::hardware::audio::effect {
-Factory::Factory() {
- // TODO: get list of library UUID and name from audio_effect.xml.
- openEffectLibrary(EqualizerTypeUUID, EqualizerSwImplUUID, std::nullopt, "libequalizersw.so");
- openEffectLibrary(EqualizerTypeUUID, EqualizerBundleImplUUID, std::nullopt, "libbundleaidl.so");
- openEffectLibrary(BassBoostTypeUUID, BassBoostSwImplUUID, std::nullopt, "libbassboostsw.so");
- openEffectLibrary(DynamicsProcessingTypeUUID, DynamicsProcessingSwImplUUID, std::nullopt,
- "libdynamicsprocessingsw.so");
- openEffectLibrary(HapticGeneratorTypeUUID, HapticGeneratorSwImplUUID, std::nullopt,
- "libhapticgeneratorsw.so");
- openEffectLibrary(LoudnessEnhancerTypeUUID, LoudnessEnhancerSwImplUUID, std::nullopt,
- "libloudnessenhancersw.so");
- openEffectLibrary(ReverbTypeUUID, ReverbSwImplUUID, std::nullopt, "libreverbsw.so");
- openEffectLibrary(VirtualizerTypeUUID, VirtualizerSwImplUUID, std::nullopt,
- "libvirtualizersw.so");
- openEffectLibrary(VisualizerTypeUUID, VisualizerSwImplUUID, std::nullopt, "libvisualizersw.so");
- openEffectLibrary(VolumeTypeUUID, VolumeSwImplUUID, std::nullopt, "libvolumesw.so");
+Factory::Factory(const std::string& file) : mConfig(EffectConfig(file)) {
+ LOG(DEBUG) << __func__ << " with config file: " << file;
+ loadEffectLibs();
}
Factory::~Factory() {
@@ -62,7 +50,7 @@
const std::optional<AudioUuid>& in_proxy_uuid,
std::vector<Descriptor::Identity>* _aidl_return) {
std::copy_if(
- mIdentityList.begin(), mIdentityList.end(), std::back_inserter(*_aidl_return),
+ mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(*_aidl_return),
[&](auto& desc) {
return (!in_type_uuid.has_value() || in_type_uuid.value() == desc.type) &&
(!in_impl_uuid.has_value() || in_impl_uuid.value() == desc.uuid) &&
@@ -172,8 +160,7 @@
return status;
}
-void Factory::openEffectLibrary(const AudioUuid& type, const AudioUuid& impl,
- const std::optional<AudioUuid>& proxy, const std::string& libName) {
+void Factory::openEffectLibrary(const AudioUuid& impl, const std::string& libName) {
std::function<void(void*)> dlClose = [](void* handle) -> void {
if (handle && dlclose(handle)) {
LOG(ERROR) << "dlclose failed " << dlerror();
@@ -187,19 +174,51 @@
return;
}
- LOG(DEBUG) << __func__ << " dlopen lib:" << libName << " for uuid:\ntype:" << type.toString()
- << "\nimpl:" << impl.toString()
- << "\nproxy:" << (proxy.has_value() ? proxy.value().toString() : "null")
+ LOG(DEBUG) << __func__ << " dlopen lib:" << libName << "\nimpl:" << impl.toString()
<< "\nhandle:" << libHandle;
mEffectLibMap.insert({impl, std::make_pair(std::move(libHandle), nullptr)});
+}
- Descriptor::Identity id;
- id.type = type;
- id.uuid = impl;
- if (proxy.has_value()) {
- id.proxy = proxy.value();
+void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLib,
+ const AudioUuid& typeUuid,
+ const std::optional<AudioUuid> proxyUuid) {
+ static const auto& libMap = mConfig.getLibraryMap();
+ const std::string& libName = configLib.name;
+ if (auto path = libMap.find(libName); path != libMap.end()) {
+ Descriptor::Identity id;
+ id.type = typeUuid;
+ id.uuid = configLib.uuid;
+ id.proxy = proxyUuid;
+ LOG(DEBUG) << __func__ << ": typeUuid " << id.type.toString() << "\nimplUuid "
+ << id.uuid.toString() << " proxyUuid "
+ << (proxyUuid.has_value() ? proxyUuid->toString() : "null");
+ openEffectLibrary(id.uuid, path->second);
+ mIdentitySet.insert(std::move(id));
+ } else {
+ LOG(ERROR) << __func__ << ": library " << libName << " not exist!";
+ return;
}
- mIdentityList.push_back(id);
+}
+
+void Factory::loadEffectLibs() {
+ const auto& configEffectsMap = mConfig.getEffectsMap();
+ for (const auto& configEffects : configEffectsMap) {
+ if (auto typeUuid = kUuidNameTypeMap.find(configEffects.first /* effect name */);
+ typeUuid != kUuidNameTypeMap.end()) {
+ const auto& configLibs = configEffects.second;
+ std::optional<AudioUuid> proxyUuid;
+ if (configLibs.proxyLibrary.has_value()) {
+ const auto& proxyLib = configLibs.proxyLibrary.value();
+ proxyUuid = proxyLib.uuid;
+ }
+ for (const auto& configLib : configLibs.libraries) {
+ createIdentityWithConfig(configLib, typeUuid->second, proxyUuid);
+ }
+ } else {
+ LOG(ERROR) << __func__ << ": can not find type UUID for effect " << configEffects.first
+ << " skipping!";
+ }
+ }
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectMain.cpp b/audio/aidl/default/EffectMain.cpp
index 3219dd6..ca81204 100644
--- a/audio/aidl/default/EffectMain.cpp
+++ b/audio/aidl/default/EffectMain.cpp
@@ -19,21 +19,31 @@
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include <system/audio_config.h>
+
+/** Default name of effect configuration file. */
+static const char* kDefaultConfigName = "audio_effects_config.xml";
int main() {
// This is a debug implementation, always enable debug logging.
android::base::SetMinimumLogSeverity(::android::base::DEBUG);
ABinderProcess_setThreadPoolMaxThreadCount(0);
+ auto configFile = android::audio_find_readable_configuration_file(kDefaultConfigName);
+ if (configFile == "") {
+ LOG(ERROR) << __func__ << ": config file " << kDefaultConfigName << " not found!";
+ return EXIT_FAILURE;
+ }
+ LOG(DEBUG) << __func__ << ": start factory with configFile:" << configFile;
auto effectFactory =
- ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>();
+ ndk::SharedRefBase::make<aidl::android::hardware::audio::effect::Factory>(configFile);
std::string serviceName = std::string() + effectFactory->descriptor + "/default";
binder_status_t status =
AServiceManager_addService(effectFactory->asBinder().get(), serviceName.c_str());
CHECK_EQ(STATUS_OK, status);
- LOG(DEBUG) << __func__ << ": effectFactoryName:" << serviceName;
+ LOG(DEBUG) << __func__ << ": effectFactory: " << serviceName << " start";
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index deaca49..6863fe3 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -25,6 +25,7 @@
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include "core-impl/Module.h"
+#include "core-impl/Telephony.h"
#include "core-impl/utils.h"
using aidl::android::hardware::audio::common::SinkMetadata;
@@ -245,6 +246,15 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
+ if (mTelephony == nullptr) {
+ mTelephony = ndk::SharedRefBase::make<Telephony>();
+ }
+ *_aidl_return = mTelephony;
+ LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdAndAdditionalData,
AudioPort* _aidl_return) {
const int32_t templateId = in_templateIdAndAdditionalData.id;
@@ -779,4 +789,60 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
+ndk::ScopedAStatus Module::getMasterMute(bool* _aidl_return) {
+ *_aidl_return = mMasterMute;
+ LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMasterMute(bool in_mute) {
+ LOG(DEBUG) << __func__ << ": " << in_mute;
+ mMasterMute = in_mute;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::getMasterVolume(float* _aidl_return) {
+ *_aidl_return = mMasterVolume;
+ LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMasterVolume(float in_volume) {
+ LOG(DEBUG) << __func__ << ": " << in_volume;
+ if (in_volume >= 0.0f && in_volume <= 1.0f) {
+ mMasterVolume = in_volume;
+ return ndk::ScopedAStatus::ok();
+ }
+ LOG(ERROR) << __func__ << ": invalid master volume value: " << in_volume;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ndk::ScopedAStatus Module::getMicMute(bool* _aidl_return) {
+ *_aidl_return = mMicMute;
+ LOG(DEBUG) << __func__ << ": returning " << *_aidl_return;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::setMicMute(bool in_mute) {
+ LOG(DEBUG) << __func__ << ": " << in_mute;
+ mMicMute = in_mute;
+ 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);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::updateScreenRotation(ScreenRotation in_rotation) {
+ LOG(DEBUG) << __func__ << ": " << toString(in_rotation);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::updateScreenState(bool in_isTurnedOn) {
+ LOG(DEBUG) << __func__ << ": " << in_isTurnedOn;
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 312df72..21dc4b6 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -85,126 +85,344 @@
return "";
}
+void StreamWorkerCommonLogic::populateReply(StreamDescriptor::Reply* reply,
+ bool isConnected) const {
+ if (isConnected) {
+ reply->status = STATUS_OK;
+ reply->observable.frames = mFrameCount;
+ reply->observable.timeNs = ::android::elapsedRealtimeNano();
+ } else {
+ reply->status = STATUS_NO_INIT;
+ }
+}
+
const std::string StreamInWorkerLogic::kThreadName = "reader";
StreamInWorkerLogic::Status StreamInWorkerLogic::cycle() {
StreamDescriptor::Command command{};
if (!mCommandMQ->readBlocking(&command, 1)) {
LOG(ERROR) << __func__ << ": reading of command from MQ failed";
+ mState = StreamDescriptor::State::ERROR;
return Status::ABORT;
}
StreamDescriptor::Reply reply{};
- if (command.code == StreamContext::COMMAND_EXIT &&
- command.fmqByteCount == mInternalCommandCookie) {
- LOG(DEBUG) << __func__ << ": received EXIT command";
- // This is an internal command, no need to reply.
- return Status::EXIT;
- } else if (command.code == StreamDescriptor::COMMAND_BURST && command.fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": received BURST read command for " << command.fmqByteCount
- << " bytes";
- usleep(3000); // Simulate a blocking call into the driver.
- const size_t byteCount = std::min({static_cast<size_t>(command.fmqByteCount),
- mDataMQ->availableToWrite(), mDataBufferSize});
- const bool isConnected = mIsConnected;
- // Simulate reading of data, or provide zeroes if the stream is not connected.
- for (size_t i = 0; i < byteCount; ++i) {
- using buffer_type = decltype(mDataBuffer)::element_type;
- constexpr int kBufferValueRange = std::numeric_limits<buffer_type>::max() -
- std::numeric_limits<buffer_type>::min() + 1;
- mDataBuffer[i] = isConnected ? (std::rand() % kBufferValueRange) +
- std::numeric_limits<buffer_type>::min()
- : 0;
- }
- bool success = byteCount > 0 ? mDataMQ->write(&mDataBuffer[0], byteCount) : true;
- if (success) {
- LOG(DEBUG) << __func__ << ": writing of " << byteCount << " bytes into data MQ"
- << " succeeded; connected? " << isConnected;
- // Frames are provided and counted regardless of connection status.
- reply.fmqByteCount = byteCount;
- mFrameCount += byteCount / mFrameSize;
- if (isConnected) {
- reply.status = STATUS_OK;
- reply.observable.frames = mFrameCount;
- reply.observable.timeNs = ::android::elapsedRealtimeNano();
+ 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>();
+ cookie == mInternalCommandCookie) {
+ LOG(DEBUG) << __func__ << ": received EXIT command";
+ setClosed();
+ // This is an internal command, no need to reply.
+ return Status::EXIT;
} else {
+ LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
+ }
+ break;
+ case Tag::start:
+ LOG(DEBUG) << __func__ << ": received START read command";
+ if (mState == StreamDescriptor::State::STANDBY ||
+ mState == StreamDescriptor::State::DRAINING) {
+ populateReply(&reply, mIsConnected);
+ mState = mState == StreamDescriptor::State::STANDBY
+ ? 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;
}
- } else {
- LOG(WARNING) << __func__ << ": writing of " << byteCount
- << " bytes of data to MQ failed";
- reply.status = STATUS_NOT_ENOUGH_DATA;
- }
- reply.latencyMs = Module::kLatencyMs;
- } else {
- LOG(WARNING) << __func__ << ": invalid command (" << command.toString()
- << ") or count: " << command.fmqByteCount;
- reply.status = STATUS_BAD_VALUE;
+ 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";
+ if (mState == StreamDescriptor::State::IDLE ||
+ mState == StreamDescriptor::State::ACTIVE ||
+ mState == StreamDescriptor::State::PAUSED ||
+ mState == StreamDescriptor::State::DRAINING) {
+ if (!read(fmqByteCount, &reply)) {
+ mState = StreamDescriptor::State::ERROR;
+ }
+ if (mState == StreamDescriptor::State::IDLE ||
+ mState == StreamDescriptor::State::PAUSED) {
+ mState = StreamDescriptor::State::ACTIVE;
+ } 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.
+ mState = StreamDescriptor::State::STANDBY;
+ }
+ } else {
+ LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ } 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;
+ } else {
+ LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ break;
}
+ reply.state = mState;
LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
if (!mReplyMQ->writeBlocking(&reply, 1)) {
LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
+ mState = StreamDescriptor::State::ERROR;
return Status::ABORT;
}
return Status::CONTINUE;
}
+bool StreamInWorkerLogic::read(size_t clientSize, StreamDescriptor::Reply* reply) {
+ // Can switch the state to ERROR if a driver error occurs.
+ const size_t byteCount = std::min({clientSize, mDataMQ->availableToWrite(), mDataBufferSize});
+ const bool isConnected = mIsConnected;
+ bool fatal = false;
+ // Simulate reading of data, or provide zeroes if the stream is not connected.
+ for (size_t i = 0; i < byteCount; ++i) {
+ using buffer_type = decltype(mDataBuffer)::element_type;
+ constexpr int kBufferValueRange = std::numeric_limits<buffer_type>::max() -
+ std::numeric_limits<buffer_type>::min() + 1;
+ mDataBuffer[i] = isConnected ? (std::rand() % kBufferValueRange) +
+ std::numeric_limits<buffer_type>::min()
+ : 0;
+ }
+ usleep(3000); // Simulate a blocking call into the driver.
+ // Set 'fatal = true' if a driver error occurs.
+ if (bool success = byteCount > 0 ? mDataMQ->write(&mDataBuffer[0], byteCount) : true; success) {
+ LOG(DEBUG) << __func__ << ": writing of " << byteCount << " bytes into data MQ"
+ << " succeeded; connected? " << isConnected;
+ // Frames are provided and counted regardless of connection status.
+ reply->fmqByteCount += byteCount;
+ mFrameCount += byteCount / mFrameSize;
+ populateReply(reply, isConnected);
+ } else {
+ LOG(WARNING) << __func__ << ": writing of " << byteCount << " bytes of data to MQ failed";
+ reply->status = STATUS_NOT_ENOUGH_DATA;
+ }
+ reply->latencyMs = Module::kLatencyMs;
+ return !fatal;
+}
+
const std::string StreamOutWorkerLogic::kThreadName = "writer";
StreamOutWorkerLogic::Status StreamOutWorkerLogic::cycle() {
StreamDescriptor::Command command{};
if (!mCommandMQ->readBlocking(&command, 1)) {
LOG(ERROR) << __func__ << ": reading of command from MQ failed";
+ mState = StreamDescriptor::State::ERROR;
return Status::ABORT;
}
StreamDescriptor::Reply reply{};
- if (command.code == StreamContext::COMMAND_EXIT &&
- command.fmqByteCount == mInternalCommandCookie) {
- LOG(DEBUG) << __func__ << ": received EXIT command";
- // This is an internal command, no need to reply.
- return Status::EXIT;
- } else if (command.code == StreamDescriptor::COMMAND_BURST && command.fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": received BURST write command for " << command.fmqByteCount
- << " bytes";
- const size_t byteCount = std::min({static_cast<size_t>(command.fmqByteCount),
- mDataMQ->availableToRead(), mDataBufferSize});
- bool success = byteCount > 0 ? mDataMQ->read(&mDataBuffer[0], byteCount) : true;
- if (success) {
- const bool isConnected = mIsConnected;
- LOG(DEBUG) << __func__ << ": reading of " << byteCount << " bytes from data MQ"
- << " succeeded; connected? " << isConnected;
- // Frames are consumed and counted regardless of connection status.
- reply.fmqByteCount = byteCount;
- mFrameCount += byteCount / mFrameSize;
- if (isConnected) {
- reply.status = STATUS_OK;
- reply.observable.frames = mFrameCount;
- reply.observable.timeNs = ::android::elapsedRealtimeNano();
+ 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>();
+ cookie == mInternalCommandCookie) {
+ LOG(DEBUG) << __func__ << ": received EXIT command";
+ setClosed();
+ // This is an internal command, no need to reply.
+ return Status::EXIT;
} else {
+ LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
+ }
+ break;
+ case Tag::start:
+ LOG(DEBUG) << __func__ << ": received START write command";
+ switch (mState) {
+ case StreamDescriptor::State::STANDBY:
+ mState = StreamDescriptor::State::IDLE;
+ break;
+ case StreamDescriptor::State::PAUSED:
+ mState = StreamDescriptor::State::ACTIVE;
+ break;
+ case StreamDescriptor::State::DRAIN_PAUSED:
+ mState = StreamDescriptor::State::PAUSED;
+ break;
+ default:
+ LOG(WARNING) << __func__ << ": START command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ if (reply.status != STATUS_INVALID_OPERATION) {
+ populateReply(&reply, mIsConnected);
+ }
+ 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
+ if (!write(fmqByteCount, &reply)) {
+ mState = StreamDescriptor::State::ERROR;
+ }
+ if (mState == StreamDescriptor::State::STANDBY ||
+ mState == StreamDescriptor::State::DRAIN_PAUSED) {
+ mState = StreamDescriptor::State::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.
+ } else {
+ LOG(WARNING) << __func__ << ": BURST command can not be handled in the state "
+ << toString(mState);
+ reply.status = STATUS_INVALID_OPERATION;
+ }
+ } 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.
+ } else {
+ LOG(WARNING) << __func__ << ": DRAIN command can not be handled in the state "
+ << toString(mState);
reply.status = STATUS_INVALID_OPERATION;
}
- usleep(3000); // Simulate a blocking call into the driver.
- } else {
- LOG(WARNING) << __func__ << ": reading of " << byteCount
- << " bytes of data from MQ failed";
- reply.status = STATUS_NOT_ENOUGH_DATA;
- }
- reply.latencyMs = Module::kLatencyMs;
- } else {
- LOG(WARNING) << __func__ << ": invalid command (" << command.toString()
- << ") or count: " << command.fmqByteCount;
- reply.status = STATUS_BAD_VALUE;
+ 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;
+ }
+ break;
+ case Tag::pause:
+ LOG(DEBUG) << __func__ << ": received PAUSE write command";
+ if (mState == StreamDescriptor::State::ACTIVE ||
+ mState == StreamDescriptor::State::DRAINING) {
+ 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;
+ case Tag::flush:
+ LOG(DEBUG) << __func__ << ": received FLUSH write command";
+ if (mState == StreamDescriptor::State::PAUSED ||
+ mState == StreamDescriptor::State::DRAIN_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;
+ }
+ break;
}
+ reply.state = mState;
LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
if (!mReplyMQ->writeBlocking(&reply, 1)) {
LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
+ mState = StreamDescriptor::State::ERROR;
return Status::ABORT;
}
return Status::CONTINUE;
}
+bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
+ const size_t readByteCount = mDataMQ->availableToRead();
+ // Amount of data that the HAL module is going to actually use.
+ const size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
+ bool fatal = false;
+ if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
+ const bool isConnected = mIsConnected;
+ LOG(DEBUG) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
+ << " succeeded; connected? " << isConnected;
+ // Frames are consumed and counted regardless of connection status.
+ reply->fmqByteCount += byteCount;
+ mFrameCount += byteCount / mFrameSize;
+ populateReply(reply, isConnected);
+ usleep(3000); // Simulate a blocking call into the driver.
+ // Set 'fatal = true' if a driver error occurs.
+ } else {
+ LOG(WARNING) << __func__ << ": reading of " << readByteCount
+ << " bytes of data from MQ failed";
+ reply->status = STATUS_NOT_ENOUGH_DATA;
+ }
+ reply->latencyMs = Module::kLatencyMs;
+ return !fatal;
+}
+
template <class Metadata, class StreamWorker>
StreamCommon<Metadata, StreamWorker>::~StreamCommon() {
- if (!mIsClosed) {
+ if (!isClosed()) {
LOG(ERROR) << __func__ << ": stream was not closed prior to destruction, resource leak";
stopWorker();
// The worker and the context should clean up by themselves via destructors.
@@ -214,13 +432,13 @@
template <class Metadata, class StreamWorker>
ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::close() {
LOG(DEBUG) << __func__;
- if (!mIsClosed) {
+ if (!isClosed()) {
stopWorker();
LOG(DEBUG) << __func__ << ": joining the worker thread...";
mWorker.stop();
LOG(DEBUG) << __func__ << ": worker thread joined";
mContext.reset();
- mIsClosed = true;
+ mWorker.setClosed();
return ndk::ScopedAStatus::ok();
} else {
LOG(ERROR) << __func__ << ": stream was already closed";
@@ -231,13 +449,14 @@
template <class Metadata, class StreamWorker>
void StreamCommon<Metadata, StreamWorker>::stopWorker() {
if (auto commandMQ = mContext.getCommandMQ(); commandMQ != nullptr) {
- LOG(DEBUG) << __func__ << ": asking the worker to stop...";
- StreamDescriptor::Command cmd;
- cmd.code = StreamContext::COMMAND_EXIT;
- cmd.fmqByteCount = mContext.getInternalCommandCookie();
- // FIXME: This can block in the case when the client wrote a command
- // while the stream worker's cycle is not running. Need to revisit
- // when implementing standby and pause/resume.
+ LOG(DEBUG) << __func__ << ": asking the worker to exit...";
+ auto cmd =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::hal_reserved_exit>(
+ 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
+ // on the HAL side can cause a deadlock.
if (!commandMQ->writeBlocking(&cmd, 1)) {
LOG(ERROR) << __func__ << ": failed to write exit command to the MQ";
}
@@ -248,7 +467,7 @@
template <class Metadata, class StreamWorker>
ndk::ScopedAStatus StreamCommon<Metadata, StreamWorker>::updateMetadata(const Metadata& metadata) {
LOG(DEBUG) << __func__;
- if (!mIsClosed) {
+ if (!isClosed()) {
mMetadata = metadata;
return ndk::ScopedAStatus::ok();
}
diff --git a/audio/aidl/default/Telephony.cpp b/audio/aidl/default/Telephony.cpp
new file mode 100644
index 0000000..1854b35
--- /dev/null
+++ b/audio/aidl/default/Telephony.cpp
@@ -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.
+ */
+
+#include <android/binder_to_string.h>
+#define LOG_TAG "AHAL_Telephony"
+#include <android-base/logging.h>
+
+#include "core-impl/Telephony.h"
+
+namespace aidl::android::hardware::audio::core {
+
+ndk::ScopedAStatus Telephony::getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) {
+ *_aidl_return = mSupportedAudioModes;
+ LOG(DEBUG) << __func__ << ": returning " << ::android::internal::ToString(*_aidl_return);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Telephony::switchAudioMode(AudioMode in_mode) {
+ if (std::find(mSupportedAudioModes.begin(), mSupportedAudioModes.end(), in_mode) !=
+ mSupportedAudioModes.end()) {
+ LOG(DEBUG) << __func__ << ": " << toString(in_mode);
+ return ndk::ScopedAStatus::ok();
+ }
+ LOG(ERROR) << __func__ << ": unsupported mode " << toString(in_mode);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
new file mode 100644
index 0000000..b6fea27
--- /dev/null
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<audio_effects_conf version="2.0" xmlns="http://schemas.android.com/audio/audio_effects_conf/v2_0">
+ <!-- Overview.
+ This example config file was copy from existing one: frameworks/av/media/libeffects/data/
+ audio_effects.xml, with effect library names updated to AIDL libraries we currently have.
+
+ All "library" attributes in "effect" element must must match a "library" element with the
+ same value of the "name" attribute.
+ All "effect" attributes in "preprocess" and "postprocess" element must match an "effect"
+ element with the same value of the "name" attribute.
+
+ AIDL EffectFactory are relying on the "name" attribute in "effect" element to identify the
+ effect type, so it's necessary to have the mapping from name to effect type UUID. Make
+ sure to either use existing effect name as key of
+ ::android::hardware::audio::effect::kUuidNameTypeMap, or add a new {name, typeUUID} map
+ item to the kUuidNameTypeMap.
+
+ Existing audio_effects.xml should working without any change as long as:
+ 1. "path" attribute of "library" element matches with the actual effect library name.
+ 2. "name" attribute of "effect" and "effectProxy" element correctly added as key of
+ kUuidNameTypeMap, with value matches Identity.type in Descriptor.aidl.
+ 3. "uuid" attribute of "effect" element matches Identity.uuid in Descriptor.aidl.
+ 4. "uuid" attribute of "effectProxy" element matches Identity.proxy in Descriptor.aidl.
+ -->
+
+ <!-- List of effect libraries to load.
+ Each library element must contain a "name" attribute and a "path" attribute giving the
+ name of a library .so file on the target device.
+ -->
+ <libraries>
+ <library name="bassboostsw" path="libbassboostsw.so"/>
+ <library name="bundle" path="libbundleaidl.so"/>
+ <library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
+ <library name="equalizersw" path="libequalizersw.so"/>
+ <library name="haptic_generatorsw" path="libhapticgeneratorsw.so"/>
+ <library name="loudness_enhancersw" path="libloudnessenhancersw.so"/>
+ <library name="reverbsw" path="libreverbsw.so"/>
+ <library name="virtualizersw" path="libvirtualizersw.so"/>
+ <library name="visualizersw" path="libvisualizersw.so"/>
+ <library name="volumesw" path="libvolumesw.so"/>
+ </libraries>
+
+ <!-- list of effects to load.
+ Each "effect" element must contain a "name", "library" and a "uuid" attribute.
+ The value of the "library" attribute must correspond to the name of one library element in
+ the "libraries" element.
+ The "name" attribute used to specific effect type, and should be mapping to a key of
+ aidl::android::hardware::audio::effect::kUuidNameTypeMap.
+ The "uuid" attribute is the implementation specific UUID as specified by the effect vendor.
+
+ Effect proxy can be supported with "effectProxy" element, each sub-element should contain
+ "library" and "uuid" attribute, all other attributes were ignored. Framework side use
+ result of IFactory.queryEffects() to decide which effect implementation should be part of
+ proxy and which not.
+
+ Only "name", "library", and "uuid" attributes in "effects" element are meaningful and
+ parsed out by EffectConfig class, all other attributes are ignored.
+ Only "name" and "uuid" attributes in "effectProxy" element are meaningful and parsed out
+ by EffectConfig class, all other attributes are ignored.
+ -->
+
+ <effects>
+ <effect name="bassboost" library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="haptic_generator" library="haptic_generatorsw" uuid="fa819110-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="loudness_enhancer" library="loudness_enhancersw" uuid="fa819610-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="reverb" library="reverbsw" uuid="fa8199c6-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="virtualizer" library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="visualizer" library="visualizersw" uuid="fa81a0f6-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="volume" library="volumesw" uuid="fa81a718-588b-11ed-9b6a-0242ac120002"/>
+ <effectProxy name="equalizer" uuid="14804144-a5ee-4d24-aa88-0002a5d5c51b">
+ <libsw library="equalizersw" uuid="0bed4300-847d-11df-bb17-0002a5d5c51b"/>
+ <libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
+ </effectProxy>
+ </effects>
+
+ <!-- Audio pre processor configurations.
+ The pre processor configuration is described in a "preprocess" element and consists in a
+ list of elements each describing pre processor settings for a given use case or "stream".
+ Each stream element has a "type" attribute corresponding to the input source used.
+ Valid types are these defined in system/hardware/interfaces/media/aidl/android/media/audio/
+ common/AudioSource.aidl.
+ Each "stream" element contains a list of "apply" elements indicating one effect to apply.
+ The effect to apply is designated by its name in the "effects" elements.
+ If there are more than one effect apply to one stream, the audio framework will apply them
+ in the same equence as they listed in "stream" element.
+
+ <preprocess>
+ <stream type="voice_communication">
+ <apply effect="aec"/>
+ <apply effect="ns"/>
+ </stream>
+ </preprocess>
+ -->
+
+ <!-- Audio post processor configurations.
+ The post processor configuration is described in a "postprocess" element and consists in a
+ list of elements each describing post processor settings for a given use case or "stream".
+ Each stream element has a "type" attribute corresponding to the stream type used.
+ Valid types are these defined in system/hardware/interfaces/media/aidl/android/media/audio/
+ common/AudioStreamType.aidl.
+ Each "stream" element contains a list of "apply" elements indicating one effect to apply.
+ The effect to apply is designated by its name in the "effects" elements.
+ If there are more than one effect apply to one stream, the audio framework will apply them
+ in the same equence as they listed in "stream" element.
+
+ <postprocess>
+ <stream type="music">
+ <apply effect="music_post_proc"/>
+ </stream>
+ <stream type="voice_call">
+ <apply effect="voice_post_proc"/>
+ </stream>
+ <stream type="notification">
+ <apply effect="notification_post_proc"/>
+ </stream>
+ </postprocess>
+ -->
+
+</audio_effects_conf>
diff --git a/audio/aidl/default/config/audio_policy_configuration.xsd b/audio/aidl/default/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..823b217
--- /dev/null
+++ b/audio/aidl/default/config/audio_policy_configuration.xsd
@@ -0,0 +1,827 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<xs:schema version="2.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <!-- List the config versions supported by audio policy. -->
+ <xs:simpleType name="version">
+ <xs:restriction base="xs:decimal">
+ <xs:enumeration value="7.0"/>
+ <xs:enumeration value="7.1"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="halVersion">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Version of the interface the hal implements. Note that this
+ relates to legacy HAL API versions since HIDL APIs are versioned
+ using other mechanisms.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:decimal">
+ <!-- List of HAL versions supported by the framework. -->
+ <xs:enumeration value="2.0"/>
+ <xs:enumeration value="3.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:element name="audioPolicyConfiguration">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="globalConfiguration" type="globalConfiguration"/>
+ <xs:element name="modules" type="modules" maxOccurs="unbounded"/>
+ <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/>
+ <xs:element name="surroundSound" type="surroundSound" minOccurs="0" />
+ </xs:sequence>
+ <xs:attribute name="version" type="version"/>
+ </xs:complexType>
+ <xs:key name="moduleNameKey">
+ <xs:selector xpath="modules/module"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:unique name="volumeTargetUniqueness">
+ <xs:selector xpath="volumes/volume"/>
+ <xs:field xpath="@stream"/>
+ <xs:field xpath="@deviceCategory"/>
+ </xs:unique>
+ <xs:key name="volumeCurveNameKey">
+ <xs:selector xpath="volumes/reference"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+ <xs:selector xpath="volumes/volume"/>
+ <xs:field xpath="@ref"/>
+ </xs:keyref>
+ </xs:element>
+ <xs:complexType name="globalConfiguration">
+ <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+ <xs:attribute name="call_screen_mode_supported" type="xs:boolean" use="optional"/>
+ <xs:attribute name="engine_library" type="engineSuffix" use="optional"/>
+ </xs:complexType>
+ <xs:complexType name="modules">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ There should be one section per audio HW module present on the platform.
+ Each <module/> contains two mandatory tags: “halVersion” and “name”.
+ The module "name" is the same as in previous .conf file.
+ Each module must contain the following sections:
+ - <devicePorts/>: a list of device descriptors for all
+ input and output devices accessible via this module.
+ This contains both permanently attached devices and removable devices.
+ - <mixPorts/>: listing all output and input streams exposed by the audio HAL
+ - <routes/>: list of possible connections between input
+ and output devices or between stream and devices.
+ A <route/> is defined by a set of 3 attributes:
+ -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix)
+ -"sink": the sink involved in this route
+ -"sources": all the sources than can be connected to the sink via this route
+ - <attachedDevices/>: permanently attached devices.
+ The attachedDevices section is a list of devices names.
+ Their names correspond to device names defined in "devicePorts" section.
+ - <defaultOutputDevice/> is the device to be used when no policy rule applies
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="module" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0">
+ <xs:unique name="attachedDevicesUniqueness">
+ <xs:selector xpath="item"/>
+ <xs:field xpath="."/>
+ </xs:unique>
+ </xs:element>
+ <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/>
+ <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/>
+ <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
+ <xs:element name="routes" type="routes" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="halVersion" type="halVersion" use="required"/>
+ </xs:complexType>
+ <xs:unique name="mixPortNameUniqueness">
+ <xs:selector xpath="mixPorts/mixPort"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ <xs:key name="devicePortNameKey">
+ <xs:selector xpath="devicePorts/devicePort"/>
+ <xs:field xpath="@tagName"/>
+ </xs:key>
+ <xs:unique name="devicePortUniqueness">
+ <xs:selector xpath="devicePorts/devicePort"/>
+ <xs:field xpath="@type"/>
+ <xs:field xpath="@address"/>
+ </xs:unique>
+ <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey">
+ <xs:selector xpath="defaultOutputDevice"/>
+ <xs:field xpath="."/>
+ </xs:keyref>
+ <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey">
+ <xs:selector xpath="attachedDevices/item"/>
+ <xs:field xpath="."/>
+ </xs:keyref>
+ <!-- The following 3 constraints try to make sure each sink port
+ is reference in one an only one route. -->
+ <xs:key name="routeSinkKey">
+ <!-- predicate [@type='sink'] does not work in xsd 1.0 -->
+ <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/>
+ <xs:field xpath="@tagName|@name"/>
+ </xs:key>
+ <xs:keyref name="routeSinkRef" refer="routeSinkKey">
+ <xs:selector xpath="routes/route"/>
+ <xs:field xpath="@sink"/>
+ </xs:keyref>
+ <xs:unique name="routeUniqueness">
+ <xs:selector xpath="routes/route"/>
+ <xs:field xpath="@sink"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="attachedDevices">
+ <xs:sequence>
+ <xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="audioInOutFlag">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ The flags indicate suggested stream attributes supported by the profile.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_PRIMARY" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_FAST" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_DEEP_BUFFER" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_NON_BLOCKING" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_HW_AV_SYNC" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_TTS" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_RAW" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_SYNC" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_DIRECT_PCM" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_MMAP_NOIRQ" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_VOIP_RX" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_INCALL_MUSIC" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_SPATIALIZER" />
+ <xs:enumeration value="AUDIO_OUTPUT_FLAG_ULTRASOUND" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_FAST" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_HW_HOTWORD" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_RAW" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_SYNC" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_MMAP_NOIRQ" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_VOIP_TX" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_HW_AV_SYNC" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_DIRECT" />
+ <xs:enumeration value="AUDIO_INPUT_FLAG_ULTRASOUND" />
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioInOutFlags">
+ <xs:list itemType="audioInOutFlag" />
+ </xs:simpleType>
+ <xs:simpleType name="role">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="sink"/>
+ <xs:enumeration value="source"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="mixPorts">
+ <xs:sequence>
+ <xs:element name="mixPort" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="gains" type="gains" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ <xs:attribute name="role" type="role" use="required"/>
+ <xs:attribute name="flags" type="audioInOutFlags"/>
+ <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/>
+ <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/>
+ <xs:attribute name="preferredUsage" type="audioUsageList">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ When choosing the mixPort of an audio track, the audioPolicy
+ first considers the mixPorts with a preferredUsage including
+ the track AudioUsage preferred .
+ If non support the track format, the other mixPorts are considered.
+ Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive
+ the audio of all apps playing with a MEDIA usage.
+ It may receive audio from ALARM if there are no audio compatible
+ <mixPort preferredUsage="AUDIO_USAGE_ALARM" />.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="recommendedMuteDurationMs" type="xs:unsignedInt"/>
+ </xs:complexType>
+ <xs:unique name="mixPortProfileUniqueness">
+ <xs:selector xpath="profile"/>
+ <xs:field xpath="format"/>
+ <xs:field xpath="samplingRate"/>
+ <xs:field xpath="channelMasks"/>
+ </xs:unique>
+ <xs:unique name="mixPortGainUniqueness">
+ <xs:selector xpath="gains/gain"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="audioDevice">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_DEVICE_NONE"/>
+
+ <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_EARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_SPEAKER"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_BLE_BROADCAST"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
+ <xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/>
+
+ <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_ARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_HDMI_EARC"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_ECHO_REFERENCE"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_BLE_HEADSET"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
+ <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="vendorExtension">
+ <!-- Vendor extension names must be prefixed by "VX_" to distinguish them from
+ AOSP values. Vendors must namespace their names to avoid conflicts. The
+ namespace part must only use capital latin characters and decimal digits and
+ consist of at least 3 characters. The part of the extension name after the
+ namespace may in addition include underscores. Example for a hypothetical
+ Google virtual reality device:
+
+ <devicePort tagName="VR" type="VX_GOOGLE_VR" role="sink" />
+ -->
+ <xs:restriction base="xs:string">
+ <xs:pattern value="VX_[A-Z0-9]{3,}_[_A-Z0-9]+"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="extendableAudioDevice">
+ <xs:union memberTypes="audioDevice vendorExtension"/>
+ </xs:simpleType>
+ <xs:simpleType name="audioFormat">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_FORMAT_DEFAULT" />
+ <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
+ <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/>
+ <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/>
+ <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/>
+ <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+ <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+ <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
+ <xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
+ <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRC"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCB"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/>
+ <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/>
+ <xs:enumeration value="AUDIO_FORMAT_WMA"/>
+ <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/>
+ <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/>
+ <xs:enumeration value="AUDIO_FORMAT_MP2"/>
+ <xs:enumeration value="AUDIO_FORMAT_QCELP"/>
+ <xs:enumeration value="AUDIO_FORMAT_DSD"/>
+ <xs:enumeration value="AUDIO_FORMAT_FLAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_ALAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_APE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/>
+ <xs:enumeration value="AUDIO_FORMAT_SBC"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
+ <xs:enumeration value="AUDIO_FORMAT_AC4"/>
+ <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+ <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_LC"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V1"/>
+ <xs:enumeration value="AUDIO_FORMAT_AAC_LATM_HE_V2"/>
+ <xs:enumeration value="AUDIO_FORMAT_CELT"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE"/>
+ <xs:enumeration value="AUDIO_FORMAT_LHDC"/>
+ <xs:enumeration value="AUDIO_FORMAT_LHDC_LL"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_TWSP"/>
+ <xs:enumeration value="AUDIO_FORMAT_LC3"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEGH_BL_L3"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEGH_BL_L4"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L3"/>
+ <xs:enumeration value="AUDIO_FORMAT_MPEGH_LC_L4"/>
+ <xs:enumeration value="AUDIO_FORMAT_IEC60958"/>
+ <xs:enumeration value="AUDIO_FORMAT_DTS_UHD"/>
+ <xs:enumeration value="AUDIO_FORMAT_DRA"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_QLEA"/>
+ <xs:enumeration value="AUDIO_FORMAT_APTX_ADAPTIVE_R4"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="extendableAudioFormat">
+ <xs:union memberTypes="audioFormat vendorExtension"/>
+ </xs:simpleType>
+ <xs:simpleType name="audioUsage">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio usage specifies the intended use case for the sound being played.
+ Please consult frameworks/base/media/java/android/media/AudioAttributes.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
+ <xs:enumeration value="AUDIO_USAGE_MEDIA" />
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+ <xs:enumeration value="AUDIO_USAGE_ALARM" />
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+ <xs:enumeration value="AUDIO_USAGE_GAME" />
+ <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
+ <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT" />
+ <xs:enumeration value="AUDIO_USAGE_EMERGENCY" />
+ <xs:enumeration value="AUDIO_USAGE_SAFETY" />
+ <xs:enumeration value="AUDIO_USAGE_VEHICLE_STATUS" />
+ <xs:enumeration value="AUDIO_USAGE_ANNOUNCEMENT" />
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioUsageList">
+ <xs:list itemType="audioUsage"/>
+ </xs:simpleType>
+ <xs:simpleType name="audioContentType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio content type expresses the general category of the content.
+ Please consult frameworks/base/media/java/android/media/AudioAttributes.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_ULTRASOUND"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="samplingRates">
+ <xs:list itemType="xs:nonNegativeInteger" />
+ </xs:simpleType>
+ <xs:simpleType name="audioChannelMask">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio channel mask specifies presence of particular channels.
+ There are two representations:
+ - representation position (traditional discrete channel specification,
+ e.g. "left", "right");
+ - indexed (this is similar to "tracks" in audio mixing, channels
+ are represented using numbers).
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_CHANNEL_NONE"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_TRI"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_TRI_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_2POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_3POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_QUAD_SIDE"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_SURROUND"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_PENTA"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1_SIDE"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_5POINT1POINT4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_6POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_7POINT1POINT4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_9POINT1POINT4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_9POINT1POINT6"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_13POINT_360RA"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_22POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_A"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_HAPTIC_AB"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB"/>
+ <xs:enumeration value="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_STEREO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_FRONT_BACK"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_6"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_2POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_2POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_3POINT0POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_3POINT1POINT2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_5POINT1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_IN_VOICE_CALL_MONO"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_1"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_2"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_3"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_4"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_5"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_6"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_7"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_8"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_9"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_10"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_11"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_12"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_13"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_14"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_15"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_16"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_17"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_18"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_19"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_20"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_21"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_22"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_23"/>
+ <xs:enumeration value="AUDIO_CHANNEL_INDEX_MASK_24"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="channelMasks">
+ <xs:list itemType="audioChannelMask" />
+ </xs:simpleType>
+ <xs:simpleType name="audioEncapsulationType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_NONE"/>
+ <xs:enumeration value="AUDIO_ENCAPSULATION_TYPE_IEC61937"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="profile">
+ <xs:attribute name="name" type="xs:token" use="optional"/>
+ <xs:attribute name="format" type="extendableAudioFormat" use="optional"/>
+ <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
+ <xs:attribute name="channelMasks" type="channelMasks" use="optional"/>
+ <xs:attribute name="encapsulationType" type="audioEncapsulationType" use="optional"/>
+ </xs:complexType>
+ <xs:simpleType name="audioGainMode">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_GAIN_MODE_JOINT"/>
+ <xs:enumeration value="AUDIO_GAIN_MODE_CHANNELS"/>
+ <xs:enumeration value="AUDIO_GAIN_MODE_RAMP"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioGainModeMaskUnrestricted">
+ <xs:list itemType="audioGainMode" />
+ </xs:simpleType>
+ <xs:simpleType name='audioGainModeMask'>
+ <xs:restriction base='audioGainModeMaskUnrestricted'>
+ <xs:minLength value='1' />
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="gains">
+ <xs:sequence>
+ <xs:element name="gain" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ <xs:attribute name="mode" type="audioGainModeMask" use="required"/>
+ <xs:attribute name="channel_mask" type="audioChannelMask" use="optional"/>
+ <xs:attribute name="minValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="maxValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="defaultValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
+ <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
+ <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+ <xs:attribute name="useForVolume" type="xs:boolean" use="optional"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="devicePorts">
+ <xs:sequence>
+ <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="gains" type="gains" minOccurs="0"/>
+ </xs:sequence>
+ <xs:attribute name="tagName" type="xs:token" use="required"/>
+ <xs:attribute name="type" type="extendableAudioDevice" use="required"/>
+ <xs:attribute name="role" type="role" use="required"/>
+ <xs:attribute name="address" type="xs:string" use="optional" default=""/>
+ <!-- Note that XSD 1.0 can not check that a type only has one default. -->
+ <xs:attribute name="default" type="xs:boolean" use="optional">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ The default device will be used if multiple have the same type
+ and no explicit route request exists for a specific device of
+ that type.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="encodedFormats" type="audioFormatsList" use="optional"
+ default="" />
+ </xs:complexType>
+ <xs:unique name="devicePortProfileUniqueness">
+ <xs:selector xpath="profile"/>
+ <xs:field xpath="format"/>
+ <xs:field xpath="samplingRate"/>
+ <xs:field xpath="channelMasks"/>
+ </xs:unique>
+ <xs:unique name="devicePortGainUniqueness">
+ <xs:selector xpath="gains/gain"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="mixType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="mix"/>
+ <xs:enumeration value="mux"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="routes">
+ <xs:sequence>
+ <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ List all available sources for a given sink.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="mixType" use="required"/>
+ <xs:attribute name="sink" type="xs:string" use="required"/>
+ <xs:attribute name="sources" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="volumes">
+ <xs:sequence>
+ <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded">
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <!-- TODO: Always require a ref for better xsd validations.
+ Currently a volume could have no points nor ref
+ as it can not be forbidden by xsd 1.0.-->
+ <xs:simpleType name="volumePoint">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Comma separated pair of number.
+ The fist one is the framework level (between 0 and 100).
+ The second one is the volume to send to the HAL.
+ The framework will interpolate volumes not specified.
+ Their MUST be at least 2 points specified.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioStreamType">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Audio stream type describing the intended use case of a stream.
+ Please consult frameworks/base/media/java/android/media/AudioSystem.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+ <xs:enumeration value="AUDIO_STREAM_RING"/>
+ <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+ <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+ <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+ <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+ <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+ <xs:enumeration value="AUDIO_STREAM_TTS"/>
+ <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+ <xs:enumeration value="AUDIO_STREAM_ASSISTANT"/>
+ <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
+ <xs:enumeration value="AUDIO_STREAM_PATCH"/>
+ <xs:enumeration value="AUDIO_STREAM_CALL_ASSISTANT"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="audioSource">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ An audio source defines the intended use case for the sound being recorded.
+ Please consult frameworks/base/media/java/android/media/MediaRecorder.java
+ for the description of each value.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_SOURCE_DEFAULT"/>
+ <xs:enumeration value="AUDIO_SOURCE_MIC"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_UPLINK"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_DOWNLINK"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_SOURCE_CAMCORDER"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_RECOGNITION"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_SOURCE_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_SOURCE_UNPROCESSED"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+ <xs:enumeration value="AUDIO_SOURCE_ECHO_REFERENCE"/>
+ <xs:enumeration value="AUDIO_SOURCE_FM_TUNER"/>
+ <xs:enumeration value="AUDIO_SOURCE_HOTWORD"/>
+ <xs:enumeration value="AUDIO_SOURCE_ULTRASOUND"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <!-- Enum values of device_category from Volume.h. -->
+ <xs:simpleType name="deviceCategory">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+ <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+ <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="volume">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Volume section defines a volume curve for a given use case and device category.
+ It contains a list of points of this curve expressing the attenuation in Millibels
+ for a given volume index from 0 to 100.
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </volume>
+
+ It may also reference a reference/@name to avoid duplicating curves.
+ <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+ ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </reference>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="stream" type="audioStreamType"/>
+ <xs:attribute name="deviceCategory" type="deviceCategory"/>
+ <xs:attribute name="ref" type="xs:token" use="optional"/>
+ </xs:complexType>
+ <xs:complexType name="reference">
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="surroundSound">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Surround Sound section provides configuration related to handling of
+ multi-channel formats.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="formats" type="surroundFormats"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="audioFormatsList">
+ <xs:list itemType="extendableAudioFormat" />
+ </xs:simpleType>
+ <xs:complexType name="surroundFormats">
+ <xs:sequence>
+ <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:attribute name="name" type="extendableAudioFormat" use="required"/>
+ <xs:attribute name="subformats" type="audioFormatsList" />
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="engineSuffix">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="configurable"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
diff --git a/audio/aidl/default/equalizer/Android.bp b/audio/aidl/default/equalizer/Android.bp
index 69d7450..8de6b1a 100644
--- a/audio/aidl/default/equalizer/Android.bp
+++ b/audio/aidl/default/equalizer/Android.bp
@@ -31,7 +31,7 @@
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
- "Equalizer.cpp",
+ "EqualizerSw.cpp",
":effectCommonFile",
],
visibility: [
diff --git a/audio/aidl/default/equalizer/Equalizer.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp
similarity index 99%
rename from audio/aidl/default/equalizer/Equalizer.cpp
rename to audio/aidl/default/equalizer/EqualizerSw.cpp
index 0e07d39..32c3969 100644
--- a/audio/aidl/default/equalizer/Equalizer.cpp
+++ b/audio/aidl/default/equalizer/EqualizerSw.cpp
@@ -23,7 +23,7 @@
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
-#include "equalizer-impl/EqualizerSw.h"
+#include "EqualizerSw.h"
using aidl::android::hardware::audio::effect::EqualizerSw;
using aidl::android::hardware::audio::effect::EqualizerSwImplUUID;
diff --git a/audio/aidl/default/include/equalizer-impl/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
similarity index 97%
rename from audio/aidl/default/include/equalizer-impl/EqualizerSw.h
rename to audio/aidl/default/equalizer/EqualizerSw.h
index dad03e1..8762f5d 100644
--- a/audio/aidl/default/include/equalizer-impl/EqualizerSw.h
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -26,7 +26,7 @@
namespace aidl::android::hardware::audio::effect {
-class EqualizerSwContext : public EffectContext {
+class EqualizerSwContext final : public EffectContext {
public:
EqualizerSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
@@ -78,7 +78,7 @@
// Add equalizer specific context for processing here
};
-class EqualizerSw : public EffectImpl {
+class EqualizerSw final : public EffectImpl {
public:
EqualizerSw() { LOG(DEBUG) << __func__; }
~EqualizerSw() {
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 61516b2..0086743 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -35,6 +35,7 @@
private:
ndk::ScopedAStatus setModuleDebug(
const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
+ ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
ndk::ScopedAStatus connectExternalDevice(
const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
@@ -70,6 +71,17 @@
bool* _aidl_return) override;
ndk::ScopedAStatus resetAudioPatch(int32_t in_patchId) override;
ndk::ScopedAStatus resetAudioPortConfig(int32_t in_portConfigId) override;
+ ndk::ScopedAStatus getMasterMute(bool* _aidl_return) override;
+ ndk::ScopedAStatus setMasterMute(bool in_mute) override;
+ ndk::ScopedAStatus getMasterVolume(float* _aidl_return) override;
+ ndk::ScopedAStatus setMasterVolume(float in_volume) override;
+ ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
+ ndk::ScopedAStatus setMicMute(bool in_mute) override;
+ ndk::ScopedAStatus updateAudioMode(
+ ::aidl::android::hardware::audio::core::AudioMode in_mode) override;
+ ndk::ScopedAStatus updateScreenRotation(
+ ::aidl::android::hardware::audio::core::IModule::ScreenRotation in_rotation) override;
+ ndk::ScopedAStatus updateScreenState(bool in_isTurnedOn) override;
void cleanUpPatch(int32_t patchId);
ndk::ScopedAStatus createStreamContext(
@@ -88,12 +100,18 @@
std::unique_ptr<internal::Configuration> mConfig;
ModuleDebug mDebug;
+ // Since it is required to return the same instance of the ITelephony, even
+ // if the client has released it on its side, we need to hold it via a strong pointer.
+ std::shared_ptr<ITelephony> mTelephony;
// ids of ports created at runtime via 'connectExternalDevice'.
std::set<int32_t> mConnectedDevicePorts;
Streams mStreams;
// Maps port ids and port config ids to patch ids.
// Multimap because both ports and configs can be used by multiple patches.
std::multimap<int32_t, int32_t> mPatches;
+ bool mMasterMute = false;
+ float mMasterVolume = 1.0f;
+ bool mMicMute = false;
};
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 488edf1..5ee0f82 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -54,8 +54,8 @@
int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
DataMQ;
- // Ensure that this value is not used by any of StreamDescriptor.COMMAND_*
- static constexpr int COMMAND_EXIT = -1;
+ // Ensure that this value is not used by any of StreamDescriptor.State enums
+ static constexpr int32_t STATE_CLOSED = -1;
StreamContext() = default;
StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
@@ -99,6 +99,10 @@
class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
public:
+ bool isClosed() const {
+ return static_cast<int32_t>(mState.load()) == StreamContext::STATE_CLOSED;
+ }
+ void setClosed() { mState = static_cast<StreamDescriptor::State>(StreamContext::STATE_CLOSED); }
void setIsConnected(bool connected) { mIsConnected = connected; }
protected:
@@ -109,9 +113,12 @@
mReplyMQ(context.getReplyMQ()),
mDataMQ(context.getDataMQ()) {}
std::string init() override;
+ void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
- // Used both by the main and worker threads.
+ // Atomic fields are used both by the main and worker threads.
std::atomic<bool> mIsConnected = false;
+ static_assert(std::atomic<StreamDescriptor::State>::is_always_lock_free);
+ std::atomic<StreamDescriptor::State> mState = StreamDescriptor::State::STANDBY;
// All fields are used on the worker thread only.
const int mInternalCommandCookie;
const size_t mFrameSize;
@@ -132,6 +139,9 @@
protected:
Status cycle() override;
+
+ private:
+ bool read(size_t clientSize, StreamDescriptor::Reply* reply);
};
using StreamInWorker = ::android::hardware::audio::common::StreamWorker<StreamInWorkerLogic>;
@@ -143,6 +153,9 @@
protected:
Status cycle() override;
+
+ private:
+ bool write(size_t clientSize, StreamDescriptor::Reply* reply);
};
using StreamOutWorker = ::android::hardware::audio::common::StreamWorker<StreamOutWorkerLogic>;
@@ -155,7 +168,7 @@
? ndk::ScopedAStatus::ok()
: ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
- bool isClosed() const { return mIsClosed; }
+ bool isClosed() const { return mWorker.isClosed(); }
void setIsConnected(bool connected) { mWorker.setIsConnected(connected); }
ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
@@ -168,9 +181,6 @@
Metadata mMetadata;
StreamContext mContext;
StreamWorker mWorker;
- // This variable is checked in the destructor which can be called on an arbitrary Binder thread,
- // thus we need to ensure that any changes made by other threads are sequentially consistent.
- std::atomic<bool> mIsClosed = false;
};
class StreamIn
diff --git a/audio/aidl/default/include/core-impl/Telephony.h b/audio/aidl/default/include/core-impl/Telephony.h
new file mode 100644
index 0000000..597f3d6
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/Telephony.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/binder_enums.h>
+
+#include <aidl/android/hardware/audio/core/BnTelephony.h>
+
+namespace aidl::android::hardware::audio::core {
+
+class Telephony : public BnTelephony {
+ private:
+ ndk::ScopedAStatus getSupportedAudioModes(std::vector<AudioMode>* _aidl_return) override;
+ ndk::ScopedAStatus switchAudioMode(AudioMode in_mode) override;
+
+ const std::vector<AudioMode> mSupportedAudioModes = {::ndk::enum_range<AudioMode>().begin(),
+ ::ndk::enum_range<AudioMode>().end()};
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index edce26b..fc6a01d 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -19,6 +19,7 @@
#include <string>
#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <android-base/logging.h>
typedef binder_exception_t (*EffectCreateFunctor)(
const ::aidl::android::media::audio::common::AudioUuid*,
@@ -101,4 +102,23 @@
} \
} while (0)
+static inline bool stringToUuid(const char* str,
+ ::aidl::android::media::audio::common::AudioUuid* uuid) {
+ RETURN_VALUE_IF(!uuid || !str, false, "nullPtr");
+
+ uint32_t tmp[10];
+ if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", tmp, tmp + 1, tmp + 2, tmp + 3,
+ tmp + 4, tmp + 5, tmp + 6, tmp + 7, tmp + 8, tmp + 9) < 10) {
+ return false;
+ }
+
+ uuid->timeLow = (uint32_t)tmp[0];
+ uuid->timeMid = (uint16_t)tmp[1];
+ uuid->timeHiAndVersion = (uint16_t)tmp[2];
+ uuid->clockSeq = (uint16_t)tmp[3];
+ uuid->node.insert(uuid->node.end(), {(uint8_t)tmp[4], (uint8_t)tmp[5], (uint8_t)tmp[6],
+ (uint8_t)tmp[7], (uint8_t)tmp[8], (uint8_t)tmp[9]});
+ return true;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 767cf6c..184a587 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -15,6 +15,8 @@
*/
#pragma once
+#include <map>
+
#include <aidl/android/media/audio/common/AudioUuid.h>
namespace aidl::android::hardware::audio::effect {
@@ -39,14 +41,14 @@
0x8f34,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-// Equalizer implementation UUID.
+// 0bed4300-847d-11df-bb17-0002a5d5c51b
static const AudioUuid EqualizerSwImplUUID = {static_cast<int32_t>(0x0bed4300),
0x847d,
0x11df,
0xbb17,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
-// Equalizer bundle implementation UUID.
+// ce772f20-847d-11df-bb17-0002a5d5c51b
static const AudioUuid EqualizerBundleImplUUID = {static_cast<int32_t>(0xce772f20),
0x847d,
0x11df,
@@ -166,4 +168,26 @@
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+/**
+ * @brief A map between effect name and effect type UUID.
+ * All <name> attribution in effect/effectProxy of audio_effects.xml should be listed in this map.
+ * We need this map is because existing audio_effects.xml don't have a type UUID defined.
+ */
+static const std::map<const std::string /* effect type */, const AudioUuid&> kUuidNameTypeMap = {
+ {"bassboost", BassBoostTypeUUID},
+ {"downmix", DownmixTypeUUID},
+ {"dynamics_processing", DynamicsProcessingTypeUUID},
+ {"equalizer", EqualizerTypeUUID},
+ {"haptic_generator", HapticGeneratorTypeUUID},
+ {"loudness_enhancer", LoudnessEnhancerTypeUUID},
+ {"reverb", ReverbTypeUUID},
+ {"reverb_env_aux", ReverbTypeUUID},
+ {"reverb_env_ins", ReverbTypeUUID},
+ {"reverb_pre_aux", ReverbTypeUUID},
+ {"reverb_pre_ins", ReverbTypeUUID},
+ {"virtualizer", VirtualizerTypeUUID},
+ {"visualizer", VisualizerTypeUUID},
+ {"volume", VolumeTypeUUID},
+};
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
index a297937..6a78eab 100644
--- a/audio/aidl/default/include/effect-impl/EffectWorker.h
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.h
@@ -62,6 +62,7 @@
}
// must implement by each effect implementation
+ // TODO: consider if this interface need adjustment to handle in-place processing
virtual IEffect::Status effectProcessImpl(float* in, float* out, int processSamples) = 0;
private:
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
new file mode 100644
index 0000000..2b904f5
--- /dev/null
+++ b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <cutils/properties.h>
+#include <tinyxml2.h>
+
+#include "effect-impl/EffectTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+/**
+ * Library contains a mapping from library name to path.
+ * Effect contains a mapping from effect name to Libraries and implementation UUID.
+ * Pre/post processor contains a mapping from processing name to effect names.
+ */
+class EffectConfig {
+ public:
+ explicit EffectConfig(const std::string& file);
+
+ // <library>
+ struct Library {
+ std::string name;
+ std::string path;
+ };
+ struct LibraryUuid {
+ std::string name; // library name
+ ::aidl::android::media::audio::common::AudioUuid uuid;
+ };
+ // <effects>
+ struct EffectLibraries {
+ std::optional<struct LibraryUuid> proxyLibrary;
+ std::vector<struct LibraryUuid> libraries;
+ };
+
+ int getSkippedElements() const { return mSkippedElements; }
+ const std::unordered_map<std::string, std::string> getLibraryMap() const { return mLibraryMap; }
+ const std::unordered_map<std::string, struct EffectLibraries> getEffectsMap() const {
+ return mEffectsMap;
+ }
+ const std::unordered_map<std::string, std::vector<std::string>> getProcessingMap() const {
+ return mProcessingMap;
+ }
+
+ private:
+ int mSkippedElements;
+ /* Parsed Libraries result */
+ std::unordered_map<std::string, std::string> mLibraryMap;
+ /* Parsed Effects result */
+ std::unordered_map<std::string, struct EffectLibraries> mEffectsMap;
+ /* Parsed pre/post processing result */
+ std::unordered_map<std::string, std::vector<std::string>> mProcessingMap;
+
+ /** @return all `node`s children that are elements and match the tag if provided. */
+ std::vector<std::reference_wrapper<const tinyxml2::XMLElement>> getChildren(
+ const tinyxml2::XMLNode& node, const char* childTag = nullptr);
+
+ /** Parse a library xml note and push the result in mLibraryMap or return false on failure. */
+ bool parseLibrary(const tinyxml2::XMLElement& xml);
+
+ /** Parse an effect from an xml element describing it.
+ * @return true and pushes the effect in mEffectsMap on success, false on failure.
+ */
+ bool parseEffect(const tinyxml2::XMLElement& xml);
+
+ bool parseStream(const tinyxml2::XMLElement& xml);
+
+ // Function to parse effect.library name and effect.uuid from xml
+ bool parseLibraryUuid(const tinyxml2::XMLElement& xml, struct LibraryUuid& libraryUuid,
+ bool isProxy = false);
+
+ const char* dump(const tinyxml2::XMLElement& element,
+ tinyxml2::XMLPrinter&& printer = {}) const;
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index d50bd63..7edace0 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -19,15 +19,17 @@
#include <any>
#include <map>
#include <optional>
+#include <set>
#include <vector>
#include <aidl/android/hardware/audio/effect/BnFactory.h>
+#include "EffectConfig.h"
namespace aidl::android::hardware::audio::effect {
class Factory : public BnFactory {
public:
- Factory();
+ explicit Factory(const std::string& file);
/**
* @brief Get identity of all effects supported by the device, with the optional filter by type
* and/or by instance UUID.
@@ -77,9 +79,10 @@
override;
private:
+ const EffectConfig mConfig;
~Factory();
- // List of effect descriptors supported by the devices.
- std::vector<Descriptor::Identity> mIdentityList;
+ // Set of effect descriptors supported by the devices.
+ std::set<Descriptor::Identity> mIdentitySet;
std::map<aidl::android::media::audio::common::AudioUuid /* implementationUUID */,
std::pair<std::unique_ptr<void, std::function<void(void*)>> /* dlHandle */,
@@ -91,10 +94,13 @@
ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
void cleanupEffectMap();
- void openEffectLibrary(
- const ::aidl::android::media::audio::common::AudioUuid& type,
- const ::aidl::android::media::audio::common::AudioUuid& impl,
- const std::optional<::aidl::android::media::audio::common::AudioUuid>& proxy,
- const std::string& libName);
+ void openEffectLibrary(const ::aidl::android::media::audio::common::AudioUuid& impl,
+ const std::string& libName);
+ void createIdentityWithConfig(
+ const EffectConfig::LibraryUuid& configLib,
+ const ::aidl::android::media::audio::common::AudioUuid& typeUuid,
+ const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
+ void loadEffectLibs();
};
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
index 51645c7..27b9169 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
@@ -76,16 +76,60 @@
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- mSpecificParam = specific.get<Parameter::Specific::loudnessEnhancer>();
- LOG(DEBUG) << __func__ << " success with: " << specific.toString();
- return ndk::ScopedAStatus::ok();
+ auto& leParam = specific.get<Parameter::Specific::loudnessEnhancer>();
+ auto tag = leParam.getTag();
+
+ switch (tag) {
+ case LoudnessEnhancer::gainMb: {
+ RETURN_IF(mContext->setLeGainMb(leParam.get<LoudnessEnhancer::gainMb>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setGainMbFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+ }
+ }
}
ndk::ScopedAStatus LoudnessEnhancerSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::loudnessEnhancerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::loudnessEnhancer>(mSpecificParam);
+ auto leId = id.get<Parameter::Id::loudnessEnhancerTag>();
+ auto leIdTag = leId.getTag();
+ switch (leIdTag) {
+ case LoudnessEnhancer::Id::commonTag:
+ return getParameterLoudnessEnhancer(leId.get<LoudnessEnhancer::Id::commonTag>(),
+ specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(leIdTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus LoudnessEnhancerSw::getParameterLoudnessEnhancer(
+ const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific) {
+ std::lock_guard lg(mMutex);
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ LoudnessEnhancer leParam;
+ switch (tag) {
+ case LoudnessEnhancer::gainMb: {
+ leParam.set<LoudnessEnhancer::gainMb>(mContext->getLeGainMb());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::loudnessEnhancer>(leParam);
return ndk::ScopedAStatus::ok();
}
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
index c0de9c1..478aebc 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
@@ -32,7 +32,16 @@
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
- // TODO: add specific context here
+
+ RetCode setLeGainMb(int gainMb) {
+ // TODO : Add implementation to apply new gain
+ mGainMb = gainMb;
+ return RetCode::SUCCESS;
+ }
+ int getLeGainMb() const { return mGainMb; }
+
+ private:
+ int mGainMb = 0; // Default Gain
};
class LoudnessEnhancerSw final : public EffectImpl {
@@ -66,7 +75,7 @@
.name = "LoudnessEnhancerSw"},
.capability = Capability::make<Capability::loudnessEnhancer>(kCapability)};
- /* parameters */
- LoudnessEnhancer mSpecificParam;
+ ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
+ Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 8de1d79..03e9fca 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -7,136 +7,72 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-cc_test {
- name: "VtsHalAudioCoreTargetTest",
+cc_defaults {
+ name: "VtsHalAudioTargetTestDefaults",
defaults: [
- "VtsHalTargetTestDefaults",
- "use_libaidlvintf_gtest_helper_static",
"latest_android_hardware_audio_common_ndk_static",
- "latest_android_hardware_audio_core_ndk_static",
"latest_android_media_audio_common_types_ndk_static",
+ "use_libaidlvintf_gtest_helper_static",
+ "VtsHalTargetTestDefaults",
],
shared_libs: [
"libbinder_ndk",
- "libcutils",
"libfmq",
],
static_libs: [
+ "android.hardware.audio.effect-V1-ndk",
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
"libaudioaidlcommon",
],
+ header_libs: ["libaudioaidl_headers"],
cflags: [
"-Wall",
"-Wextra",
"-Werror",
"-Wthread-safety",
],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
+
+cc_test {
+ name: "VtsHalAudioCoreTargetTest",
+ defaults: [
+ "VtsHalAudioTargetTestDefaults",
+ "latest_android_hardware_audio_core_ndk_static",
+ ],
+ shared_libs: [
+ "libcutils",
+ ],
srcs: [
"ModuleConfig.cpp",
"VtsHalAudioCoreTargetTest.cpp",
],
- test_suites: [
- "general-tests",
- "vts",
- ],
}
cc_test {
name: "VtsHalAudioEffectFactoryTargetTest",
- defaults: [
- "latest_android_media_audio_common_types_ndk_static",
- "VtsHalTargetTestDefaults",
- "use_libaidlvintf_gtest_helper_static",
- ],
- srcs: [
- "VtsHalAudioEffectFactoryTargetTest.cpp",
- ],
- shared_libs: [
- "libbinder_ndk",
- ],
- static_libs: [
- "android.hardware.audio.effect-V1-ndk",
- "android.hardware.common-V2-ndk",
- "android.hardware.common.fmq-V1-ndk",
- ],
- header_libs: ["libaudioaidl_headers"],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wthread-safety",
- ],
- test_suites: [
- "general-tests",
- "vts",
- ],
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalAudioEffectFactoryTargetTest.cpp"],
}
cc_test {
name: "VtsHalAudioEffectTargetTest",
- defaults: [
- "latest_android_hardware_audio_common_ndk_static",
- "latest_android_media_audio_common_types_ndk_static",
- "VtsHalTargetTestDefaults",
- "use_libaidlvintf_gtest_helper_static",
- ],
- srcs: [
- "VtsHalAudioEffectTargetTest.cpp",
- ],
- shared_libs: [
- "libbinder_ndk",
- "libfmq",
- ],
- static_libs: [
- "android.hardware.audio.effect-V1-ndk",
- "android.hardware.common-V2-ndk",
- "android.hardware.common.fmq-V1-ndk",
- "libaudioaidlcommon",
- ],
- header_libs: ["libaudioaidl_headers"],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wthread-safety",
- ],
- test_suites: [
- "general-tests",
- "vts",
- ],
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalAudioEffectTargetTest.cpp"],
}
cc_test {
name: "VtsHalEqualizerTargetTest",
- defaults: [
- "latest_android_hardware_audio_common_ndk_static",
- "latest_android_media_audio_common_types_ndk_static",
- "VtsHalTargetTestDefaults",
- "use_libaidlvintf_gtest_helper_static",
- ],
- srcs: [
- "VtsHalEqualizerTargetTest.cpp",
- ],
- shared_libs: [
- "libbinder_ndk",
- "libfmq",
- ],
- static_libs: [
- "android.hardware.audio.effect-V1-ndk",
- "android.hardware.common-V2-ndk",
- "android.hardware.common.fmq-V1-ndk",
- "libaudioaidlcommon",
- ],
- header_libs: ["libaudioaidl_headers"],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wthread-safety",
- ],
- test_suites: [
- "general-tests",
- "vts",
- ],
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalEqualizerTargetTest.cpp"],
+}
+
+cc_test {
+ name: "VtsHalLoudnessEnhancerTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalLoudnessEnhancerTargetTest.cpp"],
}
diff --git a/audio/aidl/vts/AudioHalBinderServiceUtil.h b/audio/aidl/vts/AudioHalBinderServiceUtil.h
index e928286..c8d81b1 100644
--- a/audio/aidl/vts/AudioHalBinderServiceUtil.h
+++ b/audio/aidl/vts/AudioHalBinderServiceUtil.h
@@ -21,6 +21,7 @@
#include <mutex>
#include <android-base/properties.h>
+#include <android/binder_auto_utils.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
@@ -34,7 +35,7 @@
if (mBinder == nullptr) {
LOG(ERROR) << "Failed to get service " << serviceName;
} else {
- LOG(DEBUG) << "succeed to get service " << serviceName;
+ LOG(DEBUG) << "Succeeded to get service " << serviceName;
}
return mBinder;
}
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
index 2fc109a..5e4d56a 100644
--- a/audio/aidl/vts/TestUtils.h
+++ b/audio/aidl/vts/TestUtils.h
@@ -21,15 +21,6 @@
#include <android/binder_auto_utils.h>
#include <gtest/gtest_pred_impl.h>
-namespace ndk {
-
-std::ostream& operator<<(std::ostream& str, const ScopedAStatus& status) {
- str << status.getDescription();
- return str;
-}
-
-} // namespace ndk
-
namespace android::hardware::audio::common::testing {
namespace detail {
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index 2381200..5e9aa7f 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -15,6 +15,7 @@
*/
#include <algorithm>
+#include <cmath>
#include <limits>
#include <memory>
#include <optional>
@@ -29,11 +30,12 @@
#include <Utils.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
-#include <aidl/android/hardware/audio/core/IConfig.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>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include <android-base/chrono_utils.h>
+#include <android/binder_enums.h>
#include <fmq/AidlMessageQueue.h>
#include "AudioHalBinderServiceUtil.h"
@@ -45,11 +47,13 @@
using aidl::android::hardware::audio::common::RecordTrackMetadata;
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::AudioMode;
using aidl::android::hardware::audio::core::AudioPatch;
using aidl::android::hardware::audio::core::AudioRoute;
using aidl::android::hardware::audio::core::IModule;
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::ModuleDebug;
using aidl::android::hardware::audio::core::StreamDescriptor;
using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
@@ -66,9 +70,11 @@
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Void;
using android::hardware::audio::common::isBitPositionFlagSet;
using android::hardware::audio::common::StreamLogic;
using android::hardware::audio::common::StreamWorker;
+using ndk::enum_range;
using ndk::ScopedAStatus;
template <typename T>
@@ -171,25 +177,49 @@
AudioPortConfig mConfig;
};
-class AudioCoreModule : public testing::TestWithParam<std::string> {
+template <typename PropType, class Instance, typename Getter, typename Setter>
+void TestAccessors(Instance* inst, Getter getter, Setter setter,
+ const std::vector<PropType>& validValues,
+ const std::vector<PropType>& invalidValues, bool* isSupported) {
+ PropType initialValue{};
+ ScopedAStatus status = (inst->*getter)(&initialValue);
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ *isSupported = false;
+ return;
+ }
+ *isSupported = true;
+ for (const auto v : validValues) {
+ EXPECT_IS_OK((inst->*setter)(v)) << "for valid value: " << v;
+ PropType currentValue{};
+ EXPECT_IS_OK((inst->*getter)(¤tValue));
+ EXPECT_EQ(v, currentValue);
+ }
+ for (const auto v : invalidValues) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, (inst->*setter)(v)) << "for invalid value: " << v;
+ }
+ EXPECT_IS_OK((inst->*setter)(initialValue)) << "Failed to restore the initial value";
+}
+
+// Can be used as a base for any test here, does not depend on the fixture GTest parameters.
+class AudioCoreModuleBase {
public:
// The default buffer size is used mostly for negative tests.
static constexpr int kDefaultBufferSizeFrames = 256;
- void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(ConnectToService());
+ void SetUpImpl(const std::string& moduleName) {
+ ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
debug.flags().simulateDeviceConnections = true;
ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
}
- void TearDown() override {
+ void TearDownImpl() {
if (module != nullptr) {
EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
}
}
- void ConnectToService() {
- module = IModule::fromBinder(binderUtil.connectToService(GetParam()));
+ void ConnectToService(const std::string& moduleName) {
+ module = IModule::fromBinder(binderUtil.connectToService(moduleName));
ASSERT_NE(module, nullptr);
}
@@ -269,6 +299,13 @@
WithDebugFlags debug;
};
+class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
+
+ void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+};
+
class WithDevicePortConnectedState {
public:
explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
@@ -352,21 +389,36 @@
std::unique_ptr<DataMQ> mDataMQ;
};
-class StreamCommonLogic : public StreamLogic {
+class StreamLogicDriver {
public:
- StreamDescriptor::Position getLastObservablePosition() {
- std::lock_guard<std::mutex> lock(mLock);
- return mLastReply.observable;
- }
+ 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;
+ // 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,
+ // the reply will be validated and then passed to 'processValidReply'.
+ virtual bool interceptRawReply(const StreamDescriptor::Reply& reply) = 0;
+ // Return 'false' to indicate that the contents of the reply are unexpected.
+ // Will abort the logic cycle.
+ virtual bool processValidReply(const StreamDescriptor::Reply& reply) = 0;
+};
+class StreamCommonLogic : public StreamLogic {
protected:
- explicit StreamCommonLogic(const StreamContext& context)
+ StreamCommonLogic(const StreamContext& context, StreamLogicDriver* driver)
: mCommandMQ(context.getCommandMQ()),
mReplyMQ(context.getReplyMQ()),
mDataMQ(context.getDataMQ()),
- mData(context.getBufferSizeBytes()) {}
+ mData(context.getBufferSizeBytes()),
+ mDriver(driver) {}
StreamContext::CommandMQ* getCommandMQ() const { return mCommandMQ; }
StreamContext::ReplyMQ* getReplyMQ() const { return mReplyMQ; }
+ StreamLogicDriver* getDriver() const { return mDriver; }
std::string init() override { return ""; }
@@ -374,19 +426,20 @@
StreamContext::ReplyMQ* mReplyMQ;
StreamContext::DataMQ* mDataMQ;
std::vector<int8_t> mData;
- std::mutex mLock;
- StreamDescriptor::Reply mLastReply GUARDED_BY(mLock);
+ StreamLogicDriver* const mDriver;
};
class StreamReaderLogic : public StreamCommonLogic {
public:
- explicit StreamReaderLogic(const StreamContext& context) : StreamCommonLogic(context) {}
+ StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver)
+ : StreamCommonLogic(context, driver) {}
protected:
Status cycle() override {
- StreamDescriptor::Command command{};
- command.code = StreamDescriptor::COMMAND_BURST;
- command.fmqByteCount = mData.size();
+ if (getDriver()->done()) {
+ return Status::EXIT;
+ }
+ StreamDescriptor::Command command = getDriver()->getNextCommand(mData.size());
if (!mCommandMQ->writeBlocking(&command, 1)) {
LOG(ERROR) << __func__ << ": writing of command into MQ failed";
return Status::ABORT;
@@ -396,25 +449,55 @@
LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
return Status::ABORT;
}
+ if (getDriver()->interceptRawReply(reply)) {
+ return Status::CONTINUE;
+ }
if (reply.status != STATUS_OK) {
LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
return Status::ABORT;
}
- if (reply.fmqByteCount < 0 || reply.fmqByteCount > command.fmqByteCount) {
+ if (reply.fmqByteCount < 0 ||
+ (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+ reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
LOG(ERROR) << __func__
<< ": received invalid byte count in the reply: " << reply.fmqByteCount;
return Status::ABORT;
}
- {
- std::lock_guard<std::mutex> lock(mLock);
- mLastReply = reply;
+ if (static_cast<size_t>(reply.fmqByteCount) != mDataMQ->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();
}
- const size_t readCount = std::min({mDataMQ->availableToRead(),
- static_cast<size_t>(reply.fmqByteCount), mData.size()});
- if (readCount == 0 || mDataMQ->read(mData.data(), readCount)) {
+ if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
+ return Status::ABORT;
+ }
+ if (reply.xrunFrames < 0) {
+ LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
+ return Status::ABORT;
+ }
+ if (std::find(enum_range<StreamDescriptor::State>().begin(),
+ enum_range<StreamDescriptor::State>().end(),
+ reply.state) == enum_range<StreamDescriptor::State>().end()) {
+ LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
+ 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()));
+ goto checkAcceptedReply;
+ }
+ LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
+ return Status::ABORT;
+ } // readCount == 0
+ checkAcceptedReply:
+ if (acceptedReply) {
return Status::CONTINUE;
}
- LOG(ERROR) << __func__ << ": reading of " << readCount << " data bytes from MQ failed";
+ LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
return Status::ABORT;
}
};
@@ -422,17 +505,20 @@
class StreamWriterLogic : public StreamCommonLogic {
public:
- explicit StreamWriterLogic(const StreamContext& context) : StreamCommonLogic(context) {}
+ StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver)
+ : StreamCommonLogic(context, driver) {}
protected:
Status cycle() override {
- if (!mDataMQ->write(mData.data(), mData.size())) {
+ if (getDriver()->done()) {
+ 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";
return Status::ABORT;
}
- StreamDescriptor::Command command{};
- command.code = StreamDescriptor::COMMAND_BURST;
- command.fmqByteCount = mData.size();
if (!mCommandMQ->writeBlocking(&command, 1)) {
LOG(ERROR) << __func__ << ": writing of command into MQ failed";
return Status::ABORT;
@@ -442,20 +528,45 @@
LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
return Status::ABORT;
}
+ if (getDriver()->interceptRawReply(reply)) {
+ return Status::CONTINUE;
+ }
if (reply.status != STATUS_OK) {
LOG(ERROR) << __func__ << ": received error status: " << statusToString(reply.status);
return Status::ABORT;
}
- if (reply.fmqByteCount < 0 || reply.fmqByteCount > command.fmqByteCount) {
+ if (reply.fmqByteCount < 0 ||
+ (command.getTag() == StreamDescriptor::Command::Tag::burst &&
+ reply.fmqByteCount > command.get<StreamDescriptor::Command::Tag::burst>())) {
LOG(ERROR) << __func__
<< ": received invalid byte count in the reply: " << reply.fmqByteCount;
return Status::ABORT;
}
- {
- std::lock_guard<std::mutex> lock(mLock);
- mLastReply = reply;
+ if (mDataMQ->availableToWrite() != mDataMQ->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();
+ return Status::ABORT;
}
- return Status::CONTINUE;
+ if (reply.latencyMs < 0 && reply.latencyMs != StreamDescriptor::LATENCY_UNKNOWN) {
+ LOG(ERROR) << __func__ << ": received invalid latency value: " << reply.latencyMs;
+ return Status::ABORT;
+ }
+ if (reply.xrunFrames < 0) {
+ LOG(ERROR) << __func__ << ": received invalid xrunFrames value: " << reply.xrunFrames;
+ return Status::ABORT;
+ }
+ if (std::find(enum_range<StreamDescriptor::State>().begin(),
+ enum_range<StreamDescriptor::State>().end(),
+ reply.state) == enum_range<StreamDescriptor::State>().end()) {
+ LOG(ERROR) << __func__ << ": received invalid stream state: " << toString(reply.state);
+ return Status::ABORT;
+ }
+ if (getDriver()->processValidReply(reply)) {
+ return Status::CONTINUE;
+ }
+ LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
+ return Status::ABORT;
}
};
using StreamWriter = StreamWorker<StreamWriterLogic>;
@@ -466,52 +577,6 @@
using Worker = std::conditional_t<is_input, StreamReader, StreamWriter>;
};
-// A dedicated version to test replies to invalid commands.
-class StreamInvalidCommandLogic : public StreamCommonLogic {
- public:
- StreamInvalidCommandLogic(const StreamContext& context,
- const std::vector<StreamDescriptor::Command>& commands)
- : StreamCommonLogic(context), mCommands(commands) {}
-
- std::vector<std::string> getUnexpectedStatuses() {
- std::lock_guard<std::mutex> lock(mLock);
- return mUnexpectedStatuses;
- }
-
- protected:
- Status cycle() override {
- // Send all commands in one cycle to simplify testing.
- // Extra logging helps to sort out issues with unexpected HAL behavior.
- for (const auto& command : mCommands) {
- LOG(INFO) << __func__ << ": writing command " << command.toString() << " into MQ...";
- if (!getCommandMQ()->writeBlocking(&command, 1)) {
- LOG(ERROR) << __func__ << ": writing of command into MQ failed";
- return Status::ABORT;
- }
- StreamDescriptor::Reply reply{};
- LOG(INFO) << __func__ << ": reading reply for command " << command.toString() << "...";
- if (!getReplyMQ()->readBlocking(&reply, 1)) {
- LOG(ERROR) << __func__ << ": reading of reply from MQ failed";
- return Status::ABORT;
- }
- LOG(INFO) << __func__ << ": received status " << statusToString(reply.status)
- << " for command " << command.toString();
- if (reply.status != STATUS_BAD_VALUE) {
- std::string s = command.toString();
- s.append(", ").append(statusToString(reply.status));
- std::lock_guard<std::mutex> lock(mLock);
- mUnexpectedStatuses.push_back(std::move(s));
- }
- };
- return Status::EXIT;
- }
-
- private:
- const std::vector<StreamDescriptor::Command> mCommands;
- std::mutex mLock;
- std::vector<std::string> mUnexpectedStatuses GUARDED_BY(mLock);
-};
-
template <typename Stream>
class WithStream {
public:
@@ -1208,6 +1273,152 @@
}
}
+TEST_P(AudioCoreModule, MasterMute) {
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMasterMute,
+ &IModule::setMasterMute, {false, true}, {},
+ &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Master mute is not supported";
+ }
+ // TODO: Test that master mute actually mutes output.
+}
+
+TEST_P(AudioCoreModule, MasterVolume) {
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<float>(
+ module.get(), &IModule::getMasterVolume, &IModule::setMasterVolume, {0.0f, 0.5f, 1.0f},
+ {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()},
+ &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Master volume is not supported";
+ }
+ // TODO: Test that master volume actually attenuates output.
+}
+
+TEST_P(AudioCoreModule, MicMute) {
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<bool>(module.get(), &IModule::getMicMute,
+ &IModule::setMicMute, {false, true}, {},
+ &isSupported));
+ if (!isSupported) {
+ GTEST_SKIP() << "Mic mute is not supported";
+ }
+ // TODO: Test that mic mute actually mutes input.
+}
+
+TEST_P(AudioCoreModule, UpdateAudioMode) {
+ for (const auto mode : ::ndk::enum_range<AudioMode>()) {
+ EXPECT_IS_OK(module->updateAudioMode(mode)) << toString(mode);
+ }
+ EXPECT_IS_OK(module->updateAudioMode(AudioMode::NORMAL));
+}
+
+TEST_P(AudioCoreModule, UpdateScreenRotation) {
+ for (const auto rotation : ::ndk::enum_range<IModule::ScreenRotation>()) {
+ EXPECT_IS_OK(module->updateScreenRotation(rotation)) << toString(rotation);
+ }
+ EXPECT_IS_OK(module->updateScreenRotation(IModule::ScreenRotation::DEG_0));
+}
+
+TEST_P(AudioCoreModule, UpdateScreenState) {
+ EXPECT_IS_OK(module->updateScreenState(false));
+ EXPECT_IS_OK(module->updateScreenState(true));
+}
+
+class AudioCoreTelephony : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam()));
+ ASSERT_IS_OK(module->getTelephony(&telephony));
+ }
+
+ void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+
+ std::shared_ptr<ITelephony> telephony;
+};
+
+TEST_P(AudioCoreTelephony, GetSupportedAudioModes) {
+ if (telephony == nullptr) {
+ GTEST_SKIP() << "Telephony is not supported";
+ }
+ std::vector<AudioMode> modes1;
+ ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes1));
+ const std::vector<AudioMode> kMandatoryModes = {AudioMode::NORMAL, AudioMode::RINGTONE,
+ AudioMode::IN_CALL,
+ AudioMode::IN_COMMUNICATION};
+ for (const auto mode : kMandatoryModes) {
+ EXPECT_NE(modes1.end(), std::find(modes1.begin(), modes1.end(), mode))
+ << "Mandatory mode not supported: " << toString(mode);
+ }
+ std::vector<AudioMode> modes2;
+ ASSERT_IS_OK(telephony->getSupportedAudioModes(&modes2));
+ ASSERT_EQ(modes1.size(), modes2.size())
+ << "Sizes of audio mode arrays do not match across consequent calls to "
+ << "getSupportedAudioModes";
+ std::sort(modes1.begin(), modes1.end());
+ std::sort(modes2.begin(), modes2.end());
+ EXPECT_EQ(modes1, modes2);
+};
+
+TEST_P(AudioCoreTelephony, SwitchAudioMode) {
+ if (telephony == nullptr) {
+ GTEST_SKIP() << "Telephony is not supported";
+ }
+ std::vector<AudioMode> supportedModes;
+ ASSERT_IS_OK(telephony->getSupportedAudioModes(&supportedModes));
+ std::set<AudioMode> unsupportedModes = {
+ // Start with all, remove supported ones
+ ::ndk::enum_range<AudioMode>().begin(), ::ndk::enum_range<AudioMode>().end()};
+ for (const auto mode : supportedModes) {
+ EXPECT_IS_OK(telephony->switchAudioMode(mode)) << toString(mode);
+ unsupportedModes.erase(mode);
+ }
+ for (const auto mode : unsupportedModes) {
+ EXPECT_STATUS(EX_UNSUPPORTED_OPERATION, telephony->switchAudioMode(mode)) << toString(mode);
+ }
+}
+
+class StreamLogicDriverInvalidCommand : public StreamLogicDriver {
+ public:
+ StreamLogicDriverInvalidCommand(const std::vector<StreamDescriptor::Command>& commands)
+ : mCommands(commands) {}
+
+ std::string getUnexpectedStatuses() {
+ // This method is intended to be called after the worker thread has joined,
+ // thus no extra synchronization is needed.
+ std::string s;
+ if (!mStatuses.empty()) {
+ s = std::string("Pairs of (command, actual status): ")
+ .append((android::internal::ToString(mStatuses)));
+ }
+ return s;
+ }
+
+ bool done() override { return mNextCommand >= mCommands.size(); }
+ StreamDescriptor::Command getNextCommand(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();
+ 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;
+ }
+ return true;
+ }
+ bool processValidReply(const StreamDescriptor::Reply&) override { return true; }
+
+ private:
+ const std::vector<StreamDescriptor::Command> mCommands;
+ size_t mNextCommand = 0;
+ std::vector<std::string> mStatuses;
+};
+
template <typename Stream>
class AudioStream : public AudioCoreModule {
public:
@@ -1315,19 +1526,6 @@
EXPECT_NO_FATAL_FAILURE(OpenTwiceSamePortConfigImpl(portConfig.value()));
}
- void ReadOrWrite(bool useSetupSequence2, bool validateObservablePosition) {
- const auto allPortConfigs =
- moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
- if (allPortConfigs.empty()) {
- GTEST_SKIP() << "No mix ports have attached devices";
- }
- for (const auto& portConfig : allPortConfigs) {
- EXPECT_NO_FATAL_FAILURE(
- ReadOrWriteImpl(portConfig, useSetupSequence2, validateObservablePosition))
- << portConfig.toString();
- }
- }
-
void ResetPortConfigWithOpenStream() {
const auto portConfig = moduleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
if (!portConfig.has_value()) {
@@ -1357,131 +1555,40 @@
<< stream1.getPortId();
}
- template <class Worker>
- void WaitForObservablePositionAdvance(Worker& worker) {
- static constexpr int kWriteDurationUs = 50 * 1000;
- static constexpr std::chrono::milliseconds kPositionChangeTimeout{10000};
- int64_t framesInitial;
- framesInitial = worker.getLastObservablePosition().frames;
- ASSERT_FALSE(worker.hasError());
- bool timedOut = false;
- int64_t frames = framesInitial;
- for (android::base::Timer elapsed;
- frames <= framesInitial && !worker.hasError() &&
- !(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
- usleep(kWriteDurationUs);
- frames = worker.getLastObservablePosition().frames;
- }
- EXPECT_FALSE(timedOut);
- EXPECT_FALSE(worker.hasError()) << worker.getError();
- EXPECT_GT(frames, framesInitial);
- }
-
- void ReadOrWriteImpl(const AudioPortConfig& portConfig, bool useSetupSequence2,
- bool validateObservablePosition) {
- if (!useSetupSequence2) {
- ASSERT_NO_FATAL_FAILURE(
- ReadOrWriteSetupSequence1(portConfig, validateObservablePosition));
- } else {
- ASSERT_NO_FATAL_FAILURE(
- ReadOrWriteSetupSequence2(portConfig, validateObservablePosition));
- }
- }
-
- // Set up a patch first, then open a stream.
- void ReadOrWriteSetupSequence1(const AudioPortConfig& portConfig,
- bool validateObservablePosition) {
- auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
- IOTraits<Stream>::is_input, portConfig);
- ASSERT_FALSE(devicePorts.empty());
- auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
- WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
- ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-
- WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- typename IOTraits<Stream>::Worker worker(*stream.getContext());
-
- ASSERT_TRUE(worker.start());
- ASSERT_TRUE(worker.waitForAtLeastOneCycle());
- if (validateObservablePosition) {
- ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
- }
- }
-
- // Open a stream, then set up a patch for it.
- void ReadOrWriteSetupSequence2(const AudioPortConfig& portConfig,
- bool validateObservablePosition) {
- WithStream<Stream> stream(portConfig);
- ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- typename IOTraits<Stream>::Worker worker(*stream.getContext());
-
- auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
- IOTraits<Stream>::is_input, portConfig);
- ASSERT_FALSE(devicePorts.empty());
- auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
- WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
- ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
-
- ASSERT_TRUE(worker.start());
- ASSERT_TRUE(worker.waitForAtLeastOneCycle());
- if (validateObservablePosition) {
- ASSERT_NO_FATAL_FAILURE(WaitForObservablePositionAdvance(worker));
- }
- }
-
void SendInvalidCommandImpl(const AudioPortConfig& portConfig) {
- std::vector<StreamDescriptor::Command> commands(6);
- commands[0].code = -1;
- commands[1].code = StreamDescriptor::COMMAND_BURST - 1;
- commands[2].code = std::numeric_limits<int32_t>::min();
- commands[3].code = std::numeric_limits<int32_t>::max();
- commands[4].code = StreamDescriptor::COMMAND_BURST;
- commands[4].fmqByteCount = -1;
- commands[5].code = StreamDescriptor::COMMAND_BURST;
- commands[5].fmqByteCount = std::numeric_limits<int32_t>::min();
+ 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));
- StreamWorker<StreamInvalidCommandLogic> writer(*stream.getContext(), commands);
- ASSERT_TRUE(writer.start());
- writer.waitForAtLeastOneCycle();
- auto unexpectedStatuses = writer.getUnexpectedStatuses();
- EXPECT_EQ(0UL, unexpectedStatuses.size())
- << "Pairs of (command, actual status): "
- << android::internal::ToString(unexpectedStatuses);
+ StreamLogicDriverInvalidCommand driver(commands);
+ typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver);
+ ASSERT_TRUE(worker.start());
+ worker.join();
+ EXPECT_EQ("", driver.getUnexpectedStatuses());
}
};
using AudioStreamIn = AudioStream<IStreamIn>;
using AudioStreamOut = AudioStream<IStreamOut>;
-#define TEST_IO_STREAM(method_name) \
+#define TEST_IN_AND_OUT_STREAM(method_name) \
TEST_P(AudioStreamIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
TEST_P(AudioStreamOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
-#define TEST_IO_STREAM_2(method_name, arg1, arg2) \
- TEST_P(AudioStreamIn, method_name##_##arg1##_##arg2) { \
- ASSERT_NO_FATAL_FAILURE(method_name(arg1, arg2)); \
- } \
- TEST_P(AudioStreamOut, method_name##_##arg1##_##arg2) { \
- ASSERT_NO_FATAL_FAILURE(method_name(arg1, arg2)); \
- }
-TEST_IO_STREAM(CloseTwice);
-TEST_IO_STREAM(OpenAllConfigs);
-TEST_IO_STREAM(OpenInvalidBufferSize);
-TEST_IO_STREAM(OpenInvalidDirection);
-TEST_IO_STREAM(OpenOverMaxCount);
-TEST_IO_STREAM(OpenTwiceSamePortConfig);
-// Use of constants makes comprehensible test names.
-constexpr bool SetupSequence1 = false;
-constexpr bool SetupSequence2 = true;
-constexpr bool SetupOnly = false;
-constexpr bool ValidateObservablePosition = true;
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence1, SetupOnly);
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence2, SetupOnly);
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence1, ValidateObservablePosition);
-TEST_IO_STREAM_2(ReadOrWrite, SetupSequence2, ValidateObservablePosition);
-TEST_IO_STREAM(ResetPortConfigWithOpenStream);
-TEST_IO_STREAM(SendInvalidCommand);
+TEST_IN_AND_OUT_STREAM(CloseTwice);
+TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
+TEST_IN_AND_OUT_STREAM(OpenInvalidBufferSize);
+TEST_IN_AND_OUT_STREAM(OpenInvalidDirection);
+TEST_IN_AND_OUT_STREAM(OpenOverMaxCount);
+TEST_IN_AND_OUT_STREAM(OpenTwiceSamePortConfig);
+TEST_IN_AND_OUT_STREAM(ResetPortConfigWithOpenStream);
+TEST_IN_AND_OUT_STREAM(SendInvalidCommand);
TEST_P(AudioStreamOut, OpenTwicePrimary) {
const auto mixPorts = moduleConfig->getMixPorts(false);
@@ -1523,6 +1630,165 @@
<< "when no offload info is provided for a compressed offload mix port";
}
+using CommandAndState = std::pair<StreamDescriptor::Command, StreamDescriptor::State>;
+
+class StreamLogicDefaultDriver : public StreamLogicDriver {
+ public:
+ explicit StreamLogicDefaultDriver(const std::vector<CommandAndState>& commands)
+ : mCommands(commands) {}
+
+ // The three methods below is intended to be called after the worker
+ // thread has joined, thus no extra synchronization is needed.
+ bool hasObservablePositionIncrease() const { return mObservablePositionIncrease; }
+ 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;
+ }
+ command.set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
+ } else {
+ if (actualSize != nullptr) *actualSize = 0;
+ }
+ return command;
+ }
+ 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;
+ }
+ }
+ 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());
+ LOG(ERROR) << __func__ << ": " << s;
+ mUnexpectedTransition = std::move(s);
+ return false;
+ }
+ return true;
+ }
+
+ protected:
+ const std::vector<CommandAndState>& mCommands;
+ size_t mNextCommand = 0;
+ 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 { PARAM_MODULE_NAME, PARAM_CMD_SEQ, PARAM_SETUP_SEQ };
+using StreamIoTestParameters =
+ std::tuple<std::string /*moduleName*/, NamedCommandSequence, bool /*useSetupSequence2*/>;
+template <typename Stream>
+class AudioStreamIo : public AudioCoreModuleBase,
+ public testing::TestWithParam<StreamIoTestParameters> {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(SetUpImpl(std::get<PARAM_MODULE_NAME>(GetParam())));
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ }
+
+ void Run() {
+ const auto allPortConfigs =
+ moduleConfig->getPortConfigsForMixPorts(IOTraits<Stream>::is_input);
+ if (allPortConfigs.empty()) {
+ GTEST_SKIP() << "No mix ports have attached devices";
+ }
+ for (const auto& portConfig : allPortConfigs) {
+ SCOPED_TRACE(portConfig.toString());
+ const auto& commandsAndStates = std::get<PARAM_CMD_SEQ>(GetParam()).second;
+ if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+ }
+ }
+ }
+
+ bool ValidateObservablePosition(const AudioPortConfig& /*portConfig*/) {
+ // May return false based on the portConfig, e.g. for telephony ports.
+ return true;
+ }
+
+ // Set up a patch first, then open a stream.
+ void RunStreamIoCommandsImplSeq1(const AudioPortConfig& portConfig,
+ const std::vector<CommandAndState>& commandsAndStates) {
+ auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+ IOTraits<Stream>::is_input, portConfig);
+ ASSERT_FALSE(devicePorts.empty());
+ auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+ WithAudioPatch patch(IOTraits<Stream>::is_input, portConfig, devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+ 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);
+
+ ASSERT_TRUE(worker.start());
+ worker.join();
+ EXPECT_FALSE(worker.hasError()) << worker.getError();
+ EXPECT_EQ("", driver.getUnexpectedStateTransition());
+ if (ValidateObservablePosition(portConfig)) {
+ EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+ }
+ }
+
+ // Open a stream, then set up a patch for it.
+ void RunStreamIoCommandsImplSeq2(const AudioPortConfig& portConfig,
+ const std::vector<CommandAndState>& 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);
+
+ auto devicePorts = moduleConfig->getAttachedDevicesPortsForMixPort(
+ IOTraits<Stream>::is_input, portConfig);
+ ASSERT_FALSE(devicePorts.empty());
+ auto devicePortConfig = moduleConfig->getSingleConfigForDevicePort(devicePorts[0]);
+ WithAudioPatch patch(IOTraits<Stream>::is_input, stream.getPortConfig(), devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+
+ ASSERT_TRUE(worker.start());
+ worker.join();
+ EXPECT_FALSE(worker.hasError()) << worker.getError();
+ EXPECT_EQ("", driver.getUnexpectedStateTransition());
+ if (ValidateObservablePosition(portConfig)) {
+ EXPECT_TRUE(driver.hasObservablePositionIncrease());
+ EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
+ }
+ }
+};
+using AudioStreamIoIn = AudioStreamIo<IStreamIn>;
+using AudioStreamIoOut = AudioStreamIo<IStreamOut>;
+
+#define TEST_IN_AND_OUT_STREAM_IO(method_name) \
+ TEST_P(AudioStreamIoIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
+ TEST_P(AudioStreamIoOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
+
+TEST_IN_AND_OUT_STREAM_IO(Run);
+
// Tests specific to audio patches. The fixure class is named 'AudioModulePatch'
// to avoid clashing with 'AudioPatch' class.
class AudioModulePatch : public AudioCoreModule {
@@ -1696,6 +1962,10 @@
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreModule);
+INSTANTIATE_TEST_SUITE_P(AudioCoreTelephonyTest, AudioCoreTelephony,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreTelephony);
INSTANTIATE_TEST_SUITE_P(AudioStreamInTest, AudioStreamIn,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
@@ -1704,6 +1974,117 @@
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
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)});
+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::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("_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,
+ kFlushInSeq),
+ testing::Values(false, true)),
+ GetStreamIoTestName);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoIn);
+INSTANTIATE_TEST_SUITE_P(
+ AudioStreamIoOutTest, AudioStreamIoOut,
+ testing::Combine(testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
+ testing::Values(kReadOrWriteSeq, kDrainOutSeq, kDrainPauseOutSeq,
+ kStandbySeq, kPauseOutSeq, kFlushOutSeq),
+ testing::Values(false, true)),
+ GetStreamIoTestName);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioStreamIoOut);
+
INSTANTIATE_TEST_SUITE_P(AudioPatchTest, AudioModulePatch,
testing::ValuesIn(android::getAidlHalInstanceNames(IModule::descriptor)),
android::PrintInstanceNameToString);
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
new file mode 100644
index 0000000..2ad016d
--- /dev/null
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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 <aidl/Vintf.h>
+
+#define LOG_TAG "VtsHalLoudnessEnhancerTest"
+
+#include <Utils.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::LoudnessEnhancer;
+using aidl::android::hardware::audio::effect::LoudnessEnhancerTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB };
+using LoudnessEnhancerParamTestParam = std::tuple<std::string, int>;
+
+// Every int 32 bit value is a valid gain, so testing the corner cases and one regular value.
+// TODO : Update the test values once range/capability is updated by implementation.
+const std::vector<int> kGainMbValues = {std::numeric_limits<int>::min(), 100,
+ std::numeric_limits<int>::max()};
+
+class LoudnessEnhancerParamTest : public ::testing::TestWithParam<LoudnessEnhancerParamTestParam>,
+ public EffectHelper {
+ public:
+ LoudnessEnhancerParamTest()
+ : EffectHelper(std::get<PARAM_INSTANCE_NAME>(GetParam())),
+ mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {}
+
+ void SetUp() override {
+ CreateEffectsWithUUID(LoudnessEnhancerTypeUUID);
+ initParamCommonFormat();
+ initParamCommon();
+ initParamSpecific();
+ OpenEffects(LoudnessEnhancerTypeUUID);
+ SCOPED_TRACE(testing::Message() << "gainMb: " << mParamGainMb);
+ }
+
+ void TearDown() override {
+ CloseEffects();
+ DestroyEffects();
+ CleanUp();
+ }
+
+ int mParamGainMb = 0;
+
+ void SetAndGetLoudnessEnhancerParameters() {
+ auto functor = [&](const std::shared_ptr<IEffect>& effect) {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& le = it.second;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::loudnessEnhancer>(le);
+ expectParam.set<Parameter::specific>(specific);
+ // All values are valid, set parameter should succeed
+ EXPECT_STATUS(EX_NONE, effect->setParameter(expectParam)) << expectParam.toString();
+
+ // get parameter
+ Parameter getParam;
+ Parameter::Id id;
+ LoudnessEnhancer::Id leId;
+ leId.set<LoudnessEnhancer::Id::commonTag>(tag);
+ id.set<Parameter::Id::loudnessEnhancerTag>(leId);
+ EXPECT_STATUS(EX_NONE, effect->getParameter(id, &getParam));
+
+ EXPECT_EQ(expectParam, getParam);
+ }
+ };
+ EXPECT_NO_FATAL_FAILURE(ForEachEffect(functor));
+ }
+
+ void addGainMbParam(int gainMb) {
+ LoudnessEnhancer le;
+ le.set<LoudnessEnhancer::gainMb>(gainMb);
+ mTags.push_back({LoudnessEnhancer::gainMb, le});
+ }
+
+ private:
+ std::vector<std::pair<LoudnessEnhancer::Tag, LoudnessEnhancer>> mTags;
+
+ void initParamSpecific() {
+ LoudnessEnhancer le;
+ le.set<LoudnessEnhancer::gainMb>(0);
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::loudnessEnhancer>(le);
+ setSpecific(specific);
+ }
+
+ void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(LoudnessEnhancerParamTest, SetAndGetGainMb) {
+ EXPECT_NO_FATAL_FAILURE(addGainMbParam(mParamGainMb));
+ SetAndGetLoudnessEnhancerParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ LoudnessEnhancerTest, LoudnessEnhancerParamTest,
+ ::testing::Combine(
+ testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
+ testing::ValuesIn(kGainMbValues)),
+ [](const testing::TestParamInfo<LoudnessEnhancerParamTest::ParamType>& info) {
+ std::string instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+ std::string gainMb = std::to_string(std::get<PARAM_GAIN_MB>(info.param));
+
+ std::string name = instance + "_gainMb" + gainMb;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LoudnessEnhancerParamTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index e46e5b4..0ca6a58 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -1014,9 +1014,8 @@
if (mDataPosition == 0) mOnDataStart();
const size_t dataSize = std::min(mData.size() - mDataPosition, mDataMQ->availableToWrite());
bool success = mDataMQ->write(mData.data() + mDataPosition, dataSize);
+ bool wrapped = false;
ALOGE_IF(!success, "data message queue write failed");
- mDataPosition += dataSize;
- if (mDataPosition >= mData.size()) mDataPosition = 0;
mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
uint32_t efState = 0;
@@ -1034,6 +1033,11 @@
ALOGE("bad write status: %d", writeStatus.retval);
success = false;
}
+ mDataPosition += writeStatus.reply.written;
+ if (mDataPosition >= mData.size()) {
+ mDataPosition = 0;
+ wrapped = true;
+ }
}
if (ret == -EAGAIN || ret == -EINTR) {
// Spurious wakeup. This normally retries no more than once.
@@ -1042,7 +1046,7 @@
ALOGE("bad wait status: %d", ret);
success = false;
}
- if (success && mDataPosition == 0) {
+ if (wrapped) {
success = mOnDataWrap();
}
return success;
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
similarity index 77%
copy from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
copy to automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
index 5ff45f8..9720aca 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -31,15 +31,10 @@
// 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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
- int versionNumber;
- @utf8InCpp String rpcAuthorName;
- int supportedEekCurve = 0;
- @nullable @utf8InCpp String uniqueId;
- const int CURVE_NONE = 0;
- const int CURVE_P256 = 1;
- const int CURVE_25519 = 2;
+package android.hardware.automotive.vehicle;
+@Backing(type="int") @VintfStability
+enum VehicleApPowerBootupReason {
+ USER_POWER_ON = 0,
+ SYSTEM_USER_DETECTION = 1,
+ SYSTEM_REMOTE_ACCESS = 2,
}
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 64c7ce7..f93d76f 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
@@ -119,12 +119,15 @@
DOOR_POS = 373295872,
DOOR_MOVE = 373295873,
DOOR_LOCK = 371198722,
+ DOOR_CHILD_LOCK_ENABLED = 371198723,
MIRROR_Z_POS = 339741504,
MIRROR_Z_MOVE = 339741505,
MIRROR_Y_POS = 339741506,
MIRROR_Y_MOVE = 339741507,
MIRROR_LOCK = 287312708,
MIRROR_FOLD = 287312709,
+ MIRROR_AUTO_FOLD_ENABLED = 337644358,
+ MIRROR_AUTO_TILT_ENABLED = 337644359,
SEAT_MEMORY_SELECT = 356518784,
SEAT_MEMORY_SET = 356518785,
SEAT_BELT_BUCKLED = 354421634,
@@ -152,10 +155,18 @@
SEAT_HEADREST_ANGLE_MOVE = 356518808,
SEAT_HEADREST_FORE_AFT_POS = 356518809,
SEAT_HEADREST_FORE_AFT_MOVE = 356518810,
+ SEAT_EASY_ACCESS_ENABLED = 354421661,
+ SEAT_CUSHION_SIDE_SUPPORT_POS = 356518815,
SEAT_OCCUPANCY = 356518832,
WINDOW_POS = 322964416,
WINDOW_MOVE = 322964417,
WINDOW_LOCK = 320867268,
+ STEERING_WHEEL_DEPTH_POS = 289410016,
+ STEERING_WHEEL_DEPTH_MOVE = 289410017,
+ STEERING_WHEEL_HEIGHT_POS = 289410018,
+ STEERING_WHEEL_HEIGHT_MOVE = 289410019,
+ STEERING_WHEEL_THEFT_LOCK_ENABLED = 287312868,
+ STEERING_WHEEL_LOCKED = 287312869,
VEHICLE_MAP_SERVICE = 299895808,
OBD2_LIVE_FRAME = 299896064,
OBD2_FREEZE_FRAME = 299896065,
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.aidl
new file mode 100644
index 0000000..e325b38
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerBootupReason.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.
+ */
+
+package android.hardware.automotive.vehicle;
+
+/**
+ * Vehicle AP power bootup reason.
+ */
+@VintfStability
+@Backing(type="int")
+enum VehicleApPowerBootupReason {
+ /**
+ * Power on due to user's pressing of power key or rotating of ignition
+ * switch.
+ */
+ USER_POWER_ON = 0,
+ /**
+ * Automatic power on triggered by door unlock or any other kind of automatic
+ * user detection.
+ */
+ SYSTEM_USER_DETECTION = 1,
+ /**
+ * Automatic power on to execute a remote task. This is triggered by
+ * receiving a wakeup message from TCU wakeup client.
+ */
+ SYSTEM_REMOTE_ACCESS = 2,
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 1852673..245857b 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -16,6 +16,8 @@
package android.hardware.automotive.vehicle;
+import android.hardware.automotive.vehicle.VehicleArea;
+import android.hardware.automotive.vehicle.VehiclePropertyGroup;
import android.hardware.automotive.vehicle.VehiclePropertyType;
/**
* Declares all vehicle properties. VehicleProperty has a bitwise structure.
@@ -1318,6 +1320,18 @@
DOOR_LOCK = 0x0B02 + 0x10000000 + 0x06000000
+ 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:BOOLEAN
/**
+ * Door child lock feature enabled
+ *
+ * Returns true if the door child lock feature is enabled and false if it is disabled.
+ *
+ * If enabled, the door is unable to be opened from the inside.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ DOOR_CHILD_LOCK_ENABLED =
+ 0x0B03 + VehiclePropertyGroup.SYSTEM + VehicleArea.DOOR + VehiclePropertyType.BOOLEAN,
+ /**
* Mirror Z Position
*
* Positive value indicates tilt upwards, negative value is downwards
@@ -1377,6 +1391,35 @@
*/
MIRROR_FOLD = 0x0B45 + 0x10000000 + 0x01000000
+ 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
+
+ /**
+ * Represents property for Mirror Auto Fold feature.
+ *
+ * This property is true when the feature for automatically folding the vehicle's side mirrors
+ * (for example, when the mirrors fold inward automatically when one exits and locks the
+ * vehicle) is enabled.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+
+ MIRROR_AUTO_FOLD_ENABLED =
+ 0x0B46 + VehiclePropertyGroup.SYSTEM + VehicleArea.MIRROR + VehiclePropertyType.BOOLEAN,
+
+ /**
+ * Represents property for Mirror Auto Tilt feature.
+ *
+ * This property is true when the feature for automatically tilting the vehicle's side mirrors
+ * (for example, when the mirrors tilt downward automatically when one reverses the vehicle) is
+ * enabled.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+
+ MIRROR_AUTO_TILT_ENABLED =
+ 0x0B47 + VehiclePropertyGroup.SYSTEM + VehicleArea.MIRROR + VehiclePropertyType.BOOLEAN,
+
/**
* Seat memory select
*
@@ -1679,6 +1722,33 @@
SEAT_HEADREST_FORE_AFT_MOVE = 0x0B9A + 0x10000000 + 0x05000000
+ 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
/**
+ * Represents property for Seat easy access feature.
+ *
+ * If true, the seat will automatically adjust to make it easier for the occupant to enter and
+ * exit the vehicle.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ SEAT_EASY_ACCESS_ENABLED =
+ 0x0B9D + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
+ /**
+ * Represents property for seat’s hipside (bottom cushion’s side) support position.
+ *
+ * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All integers
+ * between minInt32Value and maxInt32Value are supported.
+ *
+ * maxInt32Value indicates the widest cushion side support setting (i.e. least support).
+ * minInt32Value indicates the thinnest cushion side support setting (i.e most support).
+ *
+ * This value is not in any particular unit but in a specified range of steps.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ SEAT_CUSHION_SIDE_SUPPORT_POS =
+ 0x0B9F + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+ /**
* Seat Occupancy
*
* Indicates whether a particular seat is occupied or not, to the best of the car's ability
@@ -1748,6 +1818,100 @@
WINDOW_LOCK = 0x0BC4 + 0x10000000 + 0x03000000
+ 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
/**
+ * Steering wheel depth position
+ *
+ * All steering wheel properties' unique ids start from 0x0BE0.
+ *
+ * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+ * minInt32Value and maxInt32Value must be supported.
+ *
+ * The maxInt32Value in default area's VehicleAreaConfig indicates the steering wheel position
+ * closest to the driver. The minInt32Value in default area's VehicleAreaConfig indicates the
+ * steering wheel position furthest to the driver.
+ *
+ * This value is not in any particular unit but in a specified range of steps.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ STEERING_WHEEL_DEPTH_POS =
+ 0x0BE0 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+ /**
+ * Steering wheel depth movement
+ *
+ * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+ * minInt32Value and maxInt32Value must be supported.
+ *
+ * The maxInt32Value in default area's VehicleAreaConfig indicates the steering wheel moving
+ * towards the driver. The minInt32Value in default area's VehicleAreaConfig indicates the
+ * steering wheel moving away from the driver. Larger integers, either positive or negative,
+ * indicate a faster movement speed. Once the steering wheel reaches the positional limit, the
+ * value resets to 0.
+ *
+ * This value is not in any particular unit but in a specified range of steps.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ STEERING_WHEEL_DEPTH_MOVE =
+ 0x0BE1 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+ /**
+ * Steering wheel height position
+ *
+ * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+ * minInt32Value and maxInt32Value must be supported.
+ *
+ * The maxInt32Value in default area's VehicleAreaConfig indicates the steering wheel being in
+ * the highest position. The minInt32Value in default area's VehicleAreaConfig indicates the
+ * steering wheel being in the lowest position.
+ *
+ * This value is not in any particular unit but in a specified range of steps.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ STEERING_WHEEL_HEIGHT_POS =
+ 0x0BE2 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+ /**
+ * Steering wheel height movement
+ *
+ * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined. All values between
+ * minInt32Value and maxInt32Value must be supported.
+ *
+ * The maxInt32Value in default area's VehicleAreaConfig indicates the steering wheel moving
+ * upwards. The minInt32Value in default area's VehicleAreaConfig indicates the steering wheel
+ * moving downwards. Larger integers, either positive or negative, indicate a faster movement
+ * speed. Once the steering wheel reaches the positional limit, the value resets to 0.
+ *
+ * This value is not in any particular unit but in a specified range of steps.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ STEERING_WHEEL_HEIGHT_MOVE =
+ 0x0BE3 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
+ /**
+ * Steering wheel theft lock feature enabled
+ *
+ * If true, the steering wheel will lock automatically to prevent theft in certain
+ * situations.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ STEERING_WHEEL_THEFT_LOCK_ENABLED =
+ 0x0BE4 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+ /**
+ * Steering wheel locked
+ *
+ * If true, the steering wheel's position is locked and not changeable.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ STEERING_WHEEL_LOCKED =
+ 0x0BE5 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+ /**
* Vehicle Maps Service (VMS) message
*
* This property uses MIXED data to communicate vms messages.
@@ -2889,5 +3053,4 @@
*/
SUPPORTED_PROPERTY_IDS = 0x0F48 + 0x10000000 + 0x01000000
+ 0x00410000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
-
}
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index c91afe2..e3a3f0b 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -119,12 +119,15 @@
{VehicleProperty::DOOR_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::DOOR_MOVE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::DOOR_LOCK, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::DOOR_CHILD_LOCK_ENABLED, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::MIRROR_Z_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::MIRROR_Z_MOVE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::MIRROR_Y_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::MIRROR_Y_MOVE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::MIRROR_LOCK, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::MIRROR_FOLD, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::MIRROR_AUTO_TILT_ENABLED, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_MEMORY_SELECT, VehiclePropertyAccess::WRITE},
{VehicleProperty::SEAT_MEMORY_SET, VehiclePropertyAccess::WRITE},
{VehicleProperty::SEAT_BELT_BUCKLED, VehiclePropertyAccess::READ_WRITE},
@@ -152,10 +155,18 @@
{VehicleProperty::SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_OCCUPANCY, VehiclePropertyAccess::READ},
{VehicleProperty::WINDOW_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::WINDOW_MOVE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::WINDOW_LOCK, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::STEERING_WHEEL_DEPTH_POS, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::STEERING_WHEEL_DEPTH_MOVE, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::STEERING_WHEEL_HEIGHT_POS, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::STEERING_WHEEL_HEIGHT_MOVE, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::STEERING_WHEEL_THEFT_LOCK_ENABLED, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::STEERING_WHEEL_LOCKED, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::VEHICLE_MAP_SERVICE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::OBD2_LIVE_FRAME, VehiclePropertyAccess::READ},
{VehicleProperty::OBD2_FREEZE_FRAME, VehiclePropertyAccess::READ},
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index 807be5d..51cb60a 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -119,12 +119,15 @@
{VehicleProperty::DOOR_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::DOOR_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::DOOR_LOCK, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::DOOR_CHILD_LOCK_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::MIRROR_Z_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::MIRROR_Z_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::MIRROR_Y_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::MIRROR_Y_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::MIRROR_LOCK, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::MIRROR_FOLD, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::MIRROR_AUTO_TILT_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_MEMORY_SELECT, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_MEMORY_SET, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_BELT_BUCKLED, VehiclePropertyChangeMode::ON_CHANGE},
@@ -152,10 +155,18 @@
{VehicleProperty::SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_OCCUPANCY, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::WINDOW_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::WINDOW_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::WINDOW_LOCK, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::STEERING_WHEEL_DEPTH_POS, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::STEERING_WHEEL_DEPTH_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::STEERING_WHEEL_HEIGHT_POS, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::STEERING_WHEEL_HEIGHT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::STEERING_WHEEL_THEFT_LOCK_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::STEERING_WHEEL_LOCKED, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::VEHICLE_MAP_SERVICE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::OBD2_LIVE_FRAME, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::OBD2_FREEZE_FRAME, VehiclePropertyChangeMode::ON_CHANGE},
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index e698f84..4d10d50 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -111,12 +111,15 @@
Map.entry(VehicleProperty.DOOR_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.DOOR_MOVE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.DOOR_LOCK, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.DOOR_CHILD_LOCK_ENABLED, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.MIRROR_Z_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.MIRROR_Z_MOVE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.MIRROR_Y_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.MIRROR_Y_MOVE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.MIRROR_LOCK, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.MIRROR_FOLD, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.MIRROR_AUTO_TILT_ENABLED, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_MEMORY_SELECT, VehiclePropertyAccess.WRITE),
Map.entry(VehicleProperty.SEAT_MEMORY_SET, VehiclePropertyAccess.WRITE),
Map.entry(VehicleProperty.SEAT_BELT_BUCKLED, VehiclePropertyAccess.READ_WRITE),
@@ -144,10 +147,18 @@
Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_OCCUPANCY, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.WINDOW_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.WINDOW_MOVE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.WINDOW_LOCK, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_DEPTH_POS, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_DEPTH_MOVE, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_HEIGHT_POS, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_HEIGHT_MOVE, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_THEFT_LOCK_ENABLED, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_LOCKED, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.VEHICLE_MAP_SERVICE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.OBD2_LIVE_FRAME, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.OBD2_FREEZE_FRAME, VehiclePropertyAccess.READ),
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index fe69450..162b8d2 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -111,12 +111,15 @@
Map.entry(VehicleProperty.DOOR_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.DOOR_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.DOOR_LOCK, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.DOOR_CHILD_LOCK_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.MIRROR_Z_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.MIRROR_Z_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.MIRROR_Y_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.MIRROR_Y_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.MIRROR_LOCK, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.MIRROR_FOLD, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.MIRROR_AUTO_TILT_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_MEMORY_SELECT, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_MEMORY_SET, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_BELT_BUCKLED, VehiclePropertyChangeMode.ON_CHANGE),
@@ -144,10 +147,18 @@
Map.entry(VehicleProperty.SEAT_HEADREST_ANGLE_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_HEADREST_FORE_AFT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.SEAT_EASY_ACCESS_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_OCCUPANCY, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.WINDOW_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.WINDOW_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.WINDOW_LOCK, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_DEPTH_POS, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_DEPTH_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_HEIGHT_POS, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_HEIGHT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_THEFT_LOCK_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.STEERING_WHEEL_LOCKED, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.VEHICLE_MAP_SERVICE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.OBD2_LIVE_FRAME, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.OBD2_FREEZE_FRAME, 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 7b471e1..5a0f4a3 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -1036,6 +1036,57 @@
]
},
{
+ "property": "VehicleProperty::SEAT_EASY_ACCESS_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 1
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT"
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT"
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER",
+ "minInt32Value": -10,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::SEAT_OCCUPANCY",
"areas": [
{
@@ -1929,6 +1980,22 @@
]
},
{
+ "property": "VehicleProperty::DOOR_CHILD_LOCK_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::DOOR_2_LEFT"
+ },
+ {
+ "areaId": "Constants::DOOR_2_RIGHT"
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::DOOR_POS",
"defaultValue": {
"int32Values": [
@@ -2110,6 +2177,32 @@
}
},
{
+ "property": "VehicleProperty::MIRROR_AUTO_FOLD_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 1
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::MIRROR_DRIVER_LEFT_RIGHT"
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::MIRROR_AUTO_TILT_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 1
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::MIRROR_DRIVER_LEFT_RIGHT"
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::WINDOW_LOCK",
"areas": [
{
@@ -2193,6 +2286,82 @@
]
},
{
+ "property": "VehicleProperty::STEERING_WHEEL_DEPTH_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": 0,
+ "minInt32Value": 0,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::STEERING_WHEEL_DEPTH_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": 0,
+ "minInt32Value": -2,
+ "maxInt32Value": 2
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::STEERING_WHEEL_HEIGHT_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": 0,
+ "minInt32Value": 0,
+ "maxInt32Value": 10
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::STEERING_WHEEL_HEIGHT_MOVE",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": 0,
+ "minInt32Value": -2,
+ "maxInt32Value": 2
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::STEERING_WHEEL_THEFT_LOCK_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ }
+ },
+ {
+ "property": "VehicleProperty::STEERING_WHEEL_LOCKED",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ }
+ },
+ {
"property": "VehicleProperty::WHEEL_TICK",
"defaultValue": {
"int64Values": [
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 5de206b..d57ef64 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -44,6 +44,8 @@
using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
using ::android::getAidlHalInstanceNames;
using ::android::base::ScopedLockAssertion;
@@ -114,6 +116,9 @@
class VtsHalAutomotiveVehicleTargetTest : public testing::TestWithParam<ServiceDescriptor> {
public:
+ void verifyProperty(VehicleProperty propId, VehiclePropertyAccess access,
+ VehiclePropertyChangeMode changeMode, VehiclePropertyGroup group,
+ VehicleArea area, VehiclePropertyType propertyType);
virtual void SetUp() override {
auto descriptor = GetParam();
if (descriptor.isAidlService) {
@@ -420,6 +425,128 @@
}
}
+// Helper function to compare actual vs expected property config
+void VtsHalAutomotiveVehicleTargetTest::verifyProperty(VehicleProperty propId,
+ VehiclePropertyAccess access,
+ VehiclePropertyChangeMode changeMode,
+ VehiclePropertyGroup group, VehicleArea area,
+ VehiclePropertyType propertyType) {
+ int expectedPropId = toInt(propId);
+ int expectedAccess = toInt(access);
+ int expectedChangeMode = toInt(changeMode);
+ int expectedGroup = toInt(group);
+ int expectedArea = toInt(area);
+ int expectedPropertyType = toInt(propertyType);
+
+ auto result = mVhalClient->getPropConfigs({expectedPropId});
+ ASSERT_TRUE(result.ok()) << "Failed to get required property config, error: "
+ << result.error().message();
+
+ if (result.value().size() == 0) {
+ GTEST_SKIP() << "Property has not been implemented";
+ }
+ ASSERT_EQ(result.value().size(), 1u)
+ << StringPrintf("Expect to get exactly 1 config, got %zu", result.value().size());
+
+ const auto& config = result.value().at(0);
+ int actualPropId = config->getPropId();
+ int actualAccess = config->getAccess();
+ int actualChangeMode = config->getChangeMode();
+ int actualGroup = actualPropId & toInt(VehiclePropertyGroup::MASK);
+ int actualArea = actualPropId & toInt(VehicleArea::MASK);
+ int actualPropertyType = actualPropId & toInt(VehiclePropertyType::MASK);
+
+ ASSERT_EQ(actualPropId, expectedPropId)
+ << StringPrintf("Expect to get property ID: %i, got %i", expectedPropId, actualPropId);
+
+ if (expectedAccess == toInt(VehiclePropertyAccess::READ_WRITE)) {
+ ASSERT_TRUE(actualAccess == expectedAccess ||
+ actualAccess == toInt(VehiclePropertyAccess::READ))
+ << StringPrintf("Expect to get VehiclePropertyAccess: %i or %i, got %i",
+ expectedAccess, toInt(VehiclePropertyAccess::READ), actualAccess);
+ } else {
+ ASSERT_EQ(actualAccess, expectedAccess) << StringPrintf(
+ "Expect to get VehiclePropertyAccess: %i, got %i", expectedAccess, actualAccess);
+ }
+
+ ASSERT_EQ(actualChangeMode, expectedChangeMode)
+ << StringPrintf("Expect to get VehiclePropertyChangeMode: %i, got %i",
+ expectedChangeMode, actualChangeMode);
+ ASSERT_EQ(actualGroup, expectedGroup) << StringPrintf(
+ "Expect to get VehiclePropertyGroup: %i, got %i", expectedGroup, actualGroup);
+ ASSERT_EQ(actualArea, expectedArea)
+ << StringPrintf("Expect to get VehicleArea: %i, got %i", expectedArea, actualArea);
+ ASSERT_EQ(actualPropertyType, expectedPropertyType)
+ << StringPrintf("Expect to get VehiclePropertyType: %i, got %i", expectedPropertyType,
+ actualPropertyType);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDoorChildLockEnabledConfig) {
+ verifyProperty(VehicleProperty::DOOR_CHILD_LOCK_ENABLED, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::DOOR, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelDepthPosConfig) {
+ verifyProperty(VehicleProperty::STEERING_WHEEL_DEPTH_POS, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelDepthMoveConfig) {
+ verifyProperty(VehicleProperty::STEERING_WHEEL_DEPTH_MOVE, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelHeightPosConfig) {
+ verifyProperty(VehicleProperty::STEERING_WHEEL_HEIGHT_POS, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelHeightMoveConfig) {
+ verifyProperty(VehicleProperty::STEERING_WHEEL_HEIGHT_MOVE, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::INT32);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelTheftLockEnabledConfig) {
+ verifyProperty(VehicleProperty::STEERING_WHEEL_THEFT_LOCK_ENABLED,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySteeringWheelLockedConfig) {
+ verifyProperty(VehicleProperty::STEERING_WHEEL_LOCKED, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyMirrorAutoFoldEnabledConfig) {
+ verifyProperty(VehicleProperty::MIRROR_AUTO_FOLD_ENABLED, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::MIRROR, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyMirrorAutoTiltEnabledConfig) {
+ verifyProperty(VehicleProperty::MIRROR_AUTO_TILT_ENABLED, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::MIRROR, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatEasyAccessEnabledConfig) {
+ verifyProperty(VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::SEAT, VehiclePropertyType::BOOLEAN);
+}
+
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatCushionSideSupportPosConfig) {
+ verifyProperty(VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_POS,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
std::vector<ServiceDescriptor> getDescriptors() {
std::vector<ServiceDescriptor> descriptors;
for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {
diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp
index 167e0c7..3cd76fd 100644
--- a/biometrics/common/aidl/Android.bp
+++ b/biometrics/common/aidl/Android.bp
@@ -31,7 +31,5 @@
version: "2",
imports: [],
},
-
],
-
}
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.aidl
index d4433c5..1eb8541 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/CommonProps.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.common;
+/* @hide */
@VintfStability
parcelable CommonProps {
int sensorId;
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ComponentInfo.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ComponentInfo.aidl
index ad11dda..471ed2b 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ComponentInfo.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ComponentInfo.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.common;
+/* @hide */
@VintfStability
parcelable ComponentInfo {
String componentId;
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.aidl
index 2bc6a6d..670114f 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/ICancellationSignal.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.common;
+/* @hide */
@VintfStability
interface ICancellationSignal {
oneway void cancel();
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
index 9d1cb8f..5e184bc 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationContext.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.common;
+/* @hide */
@VintfStability
parcelable OperationContext {
int id = 0;
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl
index 3da3a6a..a5b2990 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/OperationReason.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.common;
+/* @hide */
@Backing(type="byte") @VintfStability
enum OperationReason {
UNKNOWN = 0,
diff --git a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.aidl b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.aidl
index 6675d09..aa77322 100644
--- a/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.aidl
+++ b/biometrics/common/aidl/aidl_api/android.hardware.biometrics.common/current/android/hardware/biometrics/common/SensorStrength.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.common;
+/* @hide */
@Backing(type="byte") @VintfStability
enum SensorStrength {
CONVENIENCE = 0,
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.aidl
index 2f5af5d..cdedf4f 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/CommonProps.aidl
@@ -18,7 +18,9 @@
import android.hardware.biometrics.common.ComponentInfo;
import android.hardware.biometrics.common.SensorStrength;
-
+/**
+ * @hide
+ */
@VintfStability
parcelable CommonProps {
/**
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/ComponentInfo.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/ComponentInfo.aidl
index b268eef..1da9cf6 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/ComponentInfo.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/ComponentInfo.aidl
@@ -15,7 +15,9 @@
*/
package android.hardware.biometrics.common;
-
+/**
+ * @hide
+ */
@VintfStability
parcelable ComponentInfo {
/**
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl
index 1010256..b9b1f39 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/ICancellationSignal.aidl
@@ -15,9 +15,10 @@
*/
package android.hardware.biometrics.common;
-
+/**
+ * @hide
+ */
@VintfStability
oneway interface ICancellationSignal {
void cancel();
}
-
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
index 72fe660..a1c7a1f 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/OperationContext.aidl
@@ -20,6 +20,7 @@
/**
* Additional context associated with an operation.
+ * @hide
*/
@VintfStability
parcelable OperationContext {
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl
index abc25ed..a93cebc 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/OperationReason.aidl
@@ -15,7 +15,9 @@
*/
package android.hardware.biometrics.common;
-
+/**
+ * @hide
+ */
@VintfStability
@Backing(type="byte")
enum OperationReason {
diff --git a/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.aidl b/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.aidl
index 790691c..b5c0999 100644
--- a/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.aidl
+++ b/biometrics/common/aidl/android/hardware/biometrics/common/SensorStrength.aidl
@@ -15,7 +15,9 @@
*/
package android.hardware.biometrics.common;
-
+/**
+ * @hide
+ */
@VintfStability
@Backing(type="byte")
enum SensorStrength {
@@ -40,4 +42,4 @@
* HardwareAuthToken(s).
*/
STRONG,
-}
\ No newline at end of file
+}
diff --git a/biometrics/common/util/Android.bp b/biometrics/common/util/Android.bp
index 918ef72..b990812 100644
--- a/biometrics/common/util/Android.bp
+++ b/biometrics/common/util/Android.bp
@@ -13,6 +13,6 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.biometrics.common-V2-ndk",
+ "android.hardware.biometrics.common-V3-ndk",
],
}
diff --git a/biometrics/common/util/include/util/Util.h b/biometrics/common/util/include/util/Util.h
index 29ec0f8..da19dc6 100644
--- a/biometrics/common/util/include/util/Util.h
+++ b/biometrics/common/util/include/util/Util.h
@@ -40,7 +40,7 @@
// by parts of the UI or fail if there is no latency. For example, the
// Face settings page constantly runs auth and the enrollment UI uses a
// cancel/restart cycle that requires some latency while the activities change.
-#define DEFAULT_LATENCY 800
+#define DEFAULT_LATENCY 400
class Util {
public:
@@ -66,4 +66,4 @@
}
};
-} // namespace aidl::android::hardware::biometrics
\ No newline at end of file
+} // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/face/aidl/Android.bp b/biometrics/face/aidl/Android.bp
index 0bec0c5..7b11335 100644
--- a/biometrics/face/aidl/Android.bp
+++ b/biometrics/face/aidl/Android.bp
@@ -14,9 +14,9 @@
"android/hardware/biometrics/face/**/*.aidl",
],
imports: [
- "android.hardware.biometrics.common",
+ "android.hardware.biometrics.common-V3",
"android.hardware.common-V2",
- "android.hardware.keymaster-V3",
+ "android.hardware.keymaster-V4",
],
stability: "vintf",
backend: {
diff --git a/biometrics/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
index 63a3645..876a91f 100644
--- a/biometrics/face/aidl/default/Android.bp
+++ b/biometrics/face/aidl/default/Android.bp
@@ -16,8 +16,8 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.biometrics.face-V2-ndk",
- "android.hardware.biometrics.common-V2-ndk",
+ "android.hardware.biometrics.face-V3-ndk",
+ "android.hardware.biometrics.common-V3-ndk",
"android.hardware.biometrics.common.thread",
"android.hardware.biometrics.common.util",
],
@@ -49,9 +49,9 @@
],
static_libs: [
"libandroid.hardware.biometrics.face.VirtualProps",
- "android.hardware.biometrics.face-V2-ndk",
- "android.hardware.biometrics.common-V2-ndk",
- "android.hardware.keymaster-V3-ndk",
+ "android.hardware.biometrics.face-V3-ndk",
+ "android.hardware.biometrics.common-V3-ndk",
+ "android.hardware.keymaster-V4-ndk",
"android.hardware.biometrics.common.util",
],
vendor: true,
diff --git a/biometrics/face/aidl/default/face-default.xml b/biometrics/face/aidl/default/face-default.xml
index e6ef842..8f2fbb8 100644
--- a/biometrics/face/aidl/default/face-default.xml
+++ b/biometrics/face/aidl/default/face-default.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.biometrics.face</name>
- <version>2</version>
+ <version>3</version>
<fqname>IFace/default</fqname>
</hal>
</manifest>
diff --git a/biometrics/face/aidl/vts/Android.bp b/biometrics/face/aidl/vts/Android.bp
index 4171ac3..f62c4e4 100644
--- a/biometrics/face/aidl/vts/Android.bp
+++ b/biometrics/face/aidl/vts/Android.bp
@@ -15,10 +15,10 @@
],
srcs: ["VtsHalBiometricsFaceTargetTest.cpp"],
static_libs: [
- "android.hardware.biometrics.common-V2-ndk",
- "android.hardware.biometrics.face-V2-ndk",
+ "android.hardware.biometrics.common-V3-ndk",
+ "android.hardware.biometrics.face-V3-ndk",
"android.hardware.common-V2-ndk",
- "android.hardware.keymaster-V3-ndk",
+ "android.hardware.keymaster-V4-ndk",
],
shared_libs: [
"libbinder_ndk",
diff --git a/biometrics/fingerprint/aidl/Android.bp b/biometrics/fingerprint/aidl/Android.bp
index 0bd6422..f749822 100644
--- a/biometrics/fingerprint/aidl/Android.bp
+++ b/biometrics/fingerprint/aidl/Android.bp
@@ -14,8 +14,8 @@
"android/hardware/biometrics/fingerprint/**/*.aidl",
],
imports: [
- "android.hardware.biometrics.common",
- "android.hardware.keymaster-V3",
+ "android.hardware.biometrics.common-V3",
+ "android.hardware.keymaster-V4",
],
stability: "vintf",
backend: {
@@ -41,7 +41,5 @@
"android.hardware.keymaster-V3",
],
},
-
],
-
}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
index c51aa03..0cc619f 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.fingerprint;
+/* @hide */
@Backing(type="byte") @VintfStability
enum AcquiredInfo {
UNKNOWN = 0,
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl
index af7bc3c..45ce2eb 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/Error.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.fingerprint;
+/* @hide */
@Backing(type="byte") @VintfStability
enum Error {
UNKNOWN = 0,
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
index 9c208c4..67af20d 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.fingerprint;
+/* @hide */
@Backing(type="byte") @VintfStability
enum FingerprintSensorType {
UNKNOWN = 0,
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
index 5d3df6f..0b6f300 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.fingerprint;
+/* @hide */
@VintfStability
interface IFingerprint {
android.hardware.biometrics.fingerprint.SensorProps[] getSensorProps();
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
index 30f299d..f305855 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.fingerprint;
+/* @hide */
@VintfStability
interface ISession {
void generateChallenge();
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
index 3c40ad6..be18ffe 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.fingerprint;
+/* @hide */
@VintfStability
interface ISessionCallback {
void onChallengeGenerated(in long challenge);
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl
index 43db6cf..999b324 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/PointerContext.aidl
@@ -32,7 +32,8 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.fingerprint;
-@VintfStability
+/* @hide */
+@JavaDerive(equals=true) @VintfStability
parcelable PointerContext {
int pointerId = -1;
float x = 0.000000f;
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorLocation.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorLocation.aidl
index 295fde9..dc6a62d 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorLocation.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorLocation.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.fingerprint;
+/* @hide */
@VintfStability
parcelable SensorLocation {
int displayId;
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl
index 782d289..a77d5f2 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/SensorProps.aidl
@@ -32,6 +32,7 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.biometrics.fingerprint;
+/* @hide */
@VintfStability
parcelable SensorProps {
android.hardware.biometrics.common.CommonProps commonProps;
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
index 8ec8574..d3aa98a 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfo.aidl
@@ -15,7 +15,9 @@
*/
package android.hardware.biometrics.fingerprint;
-
+/**
+ * @hide
+ */
@VintfStability
@Backing(type="byte")
enum AcquiredInfo {
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl
index e69859a..d8d47fa 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/Error.aidl
@@ -15,7 +15,9 @@
*/
package android.hardware.biometrics.fingerprint;
-
+/**
+ * @hide
+ */
@VintfStability
@Backing(type="byte")
enum Error {
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
index dbe7137..7caa154 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/FingerprintSensorType.aidl
@@ -15,7 +15,9 @@
*/
package android.hardware.biometrics.fingerprint;
-
+/**
+ * @hide
+ */
@VintfStability
@Backing(type="byte")
enum FingerprintSensorType {
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
index 75f90a1..f4febad 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -19,7 +19,9 @@
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.ISessionCallback;
import android.hardware.biometrics.fingerprint.SensorProps;
-
+/**
+ * @hide
+ */
@VintfStability
interface IFingerprint {
/**
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
index db01145..f4f7804 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -45,6 +45,7 @@
* ISession only supports execution of one non-interrupting operation at a time, regardless of
* whether it's cancellable. The framework must wait for a callback indicating the end of the
* current non-interrupting operation before a new non-interrupting operation can be started.
+ * @hide
*/
@VintfStability
interface ISession {
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
index f699966..24b169e 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -19,7 +19,9 @@
import android.hardware.biometrics.fingerprint.AcquiredInfo;
import android.hardware.biometrics.fingerprint.Error;
import android.hardware.keymaster.HardwareAuthToken;
-
+/**
+ * @hide
+ */
@VintfStability
interface ISessionCallback {
/**
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl
index e025d34..582e6cf 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/PointerContext.aidl
@@ -18,7 +18,9 @@
/**
* Additional context associated with a pointer event.
+ * @hide
*/
+@JavaDerive(equals=true)
@VintfStability
parcelable PointerContext {
/**
@@ -64,7 +66,7 @@
boolean isAod = false;
/**
- * The time of the user interaction that produced this event, in milliseconds.
+ * The time when this event was created, in milliseconds.
*
* This is obtained from MotionEvent#getEventTime, which uses SystemClock.uptimeMillis() as
* the clock.
@@ -74,10 +76,10 @@
long time = 0;
/**
- * The time of the first user interaction in this gesture, in milliseconds.
+ * This event is part of some gesture. This is the time when MotionEvent#ACTION_DOWN was
+ * created for that gesture, in milliseconds.
*
- * If this event is MotionEvent#ACTION_DOWN, it means it's the first event in this gesture,
- * and `gestureStart` will be equal to `time`.
+ * If this event is MotionEvent#ACTION_DOWN, then this value is equal to `time`.
*
* This is obtained from MotionEvent#getDownTime, which uses SystemClock.uptimeMillis() as
* the clock.
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorLocation.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorLocation.aidl
index d12605c..a065a7c 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorLocation.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorLocation.aidl
@@ -15,7 +15,9 @@
*/
package android.hardware.biometrics.fingerprint;
-
+/**
+ * @hide
+ */
@VintfStability
parcelable SensorLocation {
/**
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl
index fb516da..d4e9ec6 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/SensorProps.aidl
@@ -19,7 +19,9 @@
import android.hardware.biometrics.common.CommonProps;
import android.hardware.biometrics.fingerprint.FingerprintSensorType;
import android.hardware.biometrics.fingerprint.SensorLocation;
-
+/**
+ * @hide
+ */
@VintfStability
parcelable SensorProps {
/**
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index dc0199c..fe224c9 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -15,6 +15,7 @@
vintf_fragments: ["fingerprint-example.xml"],
local_include_dirs: ["include"],
srcs: [
+ "FakeLockoutTracker.cpp",
"FakeFingerprintEngine.cpp",
"FakeFingerprintEngineRear.cpp",
"FakeFingerprintEngineUdfps.cpp",
@@ -26,8 +27,8 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.biometrics.fingerprint-V2-ndk",
- "android.hardware.biometrics.common-V2-ndk",
+ "android.hardware.biometrics.fingerprint-V3-ndk",
+ "android.hardware.biometrics.common-V3-ndk",
"android.hardware.biometrics.common.thread",
"android.hardware.biometrics.common.util",
],
@@ -40,6 +41,7 @@
srcs: [
"tests/FakeFingerprintEngineTest.cpp",
"FakeFingerprintEngine.cpp",
+ "FakeLockoutTracker.cpp",
],
shared_libs: [
"libbase",
@@ -48,9 +50,9 @@
],
static_libs: [
"libandroid.hardware.biometrics.fingerprint.VirtualProps",
- "android.hardware.biometrics.fingerprint-V2-ndk",
- "android.hardware.biometrics.common-V2-ndk",
- "android.hardware.keymaster-V3-ndk",
+ "android.hardware.biometrics.fingerprint-V3-ndk",
+ "android.hardware.biometrics.common-V3-ndk",
+ "android.hardware.keymaster-V4-ndk",
"android.hardware.biometrics.common.util",
],
vendor: true,
@@ -65,6 +67,7 @@
"tests/FakeFingerprintEngineUdfpsTest.cpp",
"FakeFingerprintEngineUdfps.cpp",
"FakeFingerprintEngine.cpp",
+ "FakeLockoutTracker.cpp",
],
shared_libs: [
"libbase",
@@ -73,9 +76,33 @@
],
static_libs: [
"libandroid.hardware.biometrics.fingerprint.VirtualProps",
- "android.hardware.biometrics.fingerprint-V2-ndk",
- "android.hardware.biometrics.common-V2-ndk",
- "android.hardware.keymaster-V3-ndk",
+ "android.hardware.biometrics.fingerprint-V3-ndk",
+ "android.hardware.biometrics.common-V3-ndk",
+ "android.hardware.keymaster-V4-ndk",
+ "android.hardware.biometrics.common.util",
+ ],
+ vendor: true,
+ test_suites: ["general-tests"],
+ require_root: true,
+}
+
+cc_test {
+ name: "android.hardware.biometrics.fingerprint.FakeLockoutTrackerTest",
+ local_include_dirs: ["include"],
+ srcs: [
+ "tests/FakeLockoutTrackerTest.cpp",
+ "FakeLockoutTracker.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.biometrics.common.thread",
+ ],
+ static_libs: [
+ "libandroid.hardware.biometrics.fingerprint.VirtualProps",
+ "android.hardware.biometrics.fingerprint-V3-ndk",
+ "android.hardware.biometrics.common-V3-ndk",
+ "android.hardware.keymaster-V4-ndk",
"android.hardware.biometrics.common.util",
],
vendor: true,
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 651c9dc..90ec8f2 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -15,6 +15,7 @@
*/
#include "FakeFingerprintEngine.h"
+#include <regex>
#include "Fingerprint.h"
#include <android-base/logging.h>
@@ -47,7 +48,7 @@
void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
const keymaster::HardwareAuthToken& hat,
const std::future<void>& cancel) {
- BEGIN_OP(FingerprintHalProperties::operation_enroll_latency().value_or(DEFAULT_LATENCY));
+ BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency()));
// Do proper HAT verification in the real implementation.
if (hat.mac.empty()) {
@@ -117,7 +118,7 @@
void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* operationId */,
const std::future<void>& cancel) {
- BEGIN_OP(FingerprintHalProperties::operation_authenticate_latency().value_or(DEFAULT_LATENCY));
+ BEGIN_OP(getLatency(FingerprintHalProperties::operation_authenticate_latency()));
int64_t now = Util::getSystemNanoTime();
int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(10);
@@ -131,10 +132,23 @@
return;
}
+ // got lockout?
+ FakeLockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode();
+ if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) {
+ LOG(ERROR) << "Fail: lockout permanent";
+ cb->onLockoutPermanent();
+ return;
+ } else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) {
+ int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft();
+ LOG(ERROR) << "Fail: lockout timed " << timeLeft;
+ cb->onLockoutTimed(timeLeft);
+ }
+
int i = 0;
do {
if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
LOG(ERROR) << "Fail: operation_authenticate_fails";
+ mLockoutTracker.addFailedAttempt();
cb->onAuthenticationFailed();
return;
}
@@ -174,20 +188,30 @@
auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
if (id > 0 && isEnrolled) {
cb->onAuthenticationSucceeded(id, {} /* hat */);
+ mLockoutTracker.reset();
return;
} else {
LOG(ERROR) << "Fail: fingerprint not enrolled";
cb->onAuthenticationFailed();
+ mLockoutTracker.addFailedAttempt();
}
}
void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
const std::future<void>& cancel) {
- BEGIN_OP(FingerprintHalProperties::operation_detect_interaction_latency().value_or(
- DEFAULT_LATENCY));
+ BEGIN_OP(getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
int64_t duration =
FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
+
+ auto detectInteractionSupported =
+ FingerprintHalProperties::detect_interaction().value_or(false);
+ if (!detectInteractionSupported) {
+ LOG(ERROR) << "Detect interaction is not supported";
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+ return;
+ }
+
auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
auto acquiredInfos = parseIntSequence(acquired);
int N = acquiredInfos.size();
@@ -308,6 +332,7 @@
}
FingerprintHalProperties::lockout(false);
cb->onLockoutCleared();
+ mLockoutTracker.reset();
}
ndk::ScopedAStatus FakeFingerprintEngine::onPointerDownImpl(int32_t /*pointerId*/, int32_t /*x*/,
@@ -383,49 +408,52 @@
return res;
}
-std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
- const std::string& str) {
+bool FakeFingerprintEngine::parseEnrollmentCaptureSingle(const std::string& str,
+ std::vector<std::vector<int32_t>>& res) {
std::vector<int32_t> defaultAcquiredInfo = {(int32_t)AcquiredInfo::GOOD};
- std::vector<std::vector<int32_t>> res;
- int i = 0, N = str.length();
- std::size_t found = 0;
bool aborted = true;
- while (found != std::string::npos) {
- std::string durationStr, acquiredStr;
- found = str.find_first_of("-,", i);
- if (found == std::string::npos) {
- if (N - i < 1) break;
- durationStr = str.substr(i, N - i);
- } else {
- durationStr = str.substr(i, found - i);
- if (str[found] == '-') {
- found = str.find_first_of('[', found + 1);
- if (found == std::string::npos) break;
- i = found + 1;
- found = str.find_first_of(']', found + 1);
- if (found == std::string::npos) break;
- acquiredStr = str.substr(i, found - i);
- found = str.find_first_of(',', found + 1);
- }
- }
- std::vector<int32_t> duration{0};
- if (!ParseInt(durationStr, &duration[0])) break;
- res.push_back(duration);
- if (!acquiredStr.empty()) {
- std::vector<int32_t> acquiredInfo = parseIntSequence(acquiredStr);
- if (acquiredInfo.empty()) break;
- res.push_back(acquiredInfo);
+ do {
+ std::smatch sms;
+ // Parses strings like "1000-[5,1]" or "500"
+ std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
+ if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
+ int32_t duration;
+ if (!ParseInt(sms.str(2), &duration)) break;
+ res.push_back({duration});
+ if (!sms.str(4).empty()) {
+ auto acqv = parseIntSequence(sms.str(4));
+ if (acqv.empty()) break;
+ res.push_back(acqv);
} else
res.push_back(defaultAcquiredInfo);
+ aborted = false;
+ } while (0);
- i = found + 1;
- if (found == std::string::npos || found == N - 1) aborted = false;
+ return !aborted;
+}
+
+std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
+ const std::string& str) {
+ std::vector<std::vector<int32_t>> res;
+
+ std::string s(str);
+ s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
+ bool aborted = false;
+ std::smatch sms;
+ // Parses strings like "1000-[5,1],500,800-[6,5,1]"
+ // ---------- --- -----------
+ // into parts: A B C
+ while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
+ if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
+ aborted = true;
+ break;
+ }
+ s = sms.suffix();
}
-
- if (aborted) {
- LOG(ERROR) << "Failed to parse enrollment captures:" + str;
+ if (aborted || s.length() != 0) {
res.clear();
+ LOG(ERROR) << "Failed to parse enrollment captures:" + str;
}
return res;
@@ -455,4 +483,34 @@
return res;
}
+int32_t FakeFingerprintEngine::getLatency(
+ const std::vector<std::optional<std::int32_t>>& latencyIn) {
+ int32_t res = DEFAULT_LATENCY;
+
+ std::vector<int32_t> latency;
+ for (auto x : latencyIn)
+ if (x.has_value()) latency.push_back(*x);
+
+ switch (latency.size()) {
+ case 0:
+ break;
+ case 1:
+ res = latency[0];
+ break;
+ case 2:
+ res = getRandomInRange(latency[0], latency[1]);
+ break;
+ default:
+ LOG(ERROR) << "ERROR: unexpected input of size " << latency.size();
+ break;
+ }
+
+ return res;
+}
+
+int32_t FakeFingerprintEngine::getRandomInRange(int32_t bound1, int32_t bound2) {
+ std::uniform_int_distribution<int32_t> dist(std::min(bound1, bound2), std::max(bound1, bound2));
+ return dist(mRandom);
+}
+
} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
index d8579a4..3cdfc70 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
@@ -23,10 +23,16 @@
#include "util/CancellationSignal.h"
#include "util/Util.h"
+#undef LOG_TAG
+#define LOG_TAG "FingerprintVirtualHalUdfps"
+
using namespace ::android::fingerprint::virt;
namespace aidl::android::hardware::biometrics::fingerprint {
+FakeFingerprintEngineUdfps::FakeFingerprintEngineUdfps()
+ : FakeFingerprintEngine(), mWorkMode(WorkMode::kIdle), mPointerDownTime(0), mUiReadyTime(0) {}
+
SensorLocation FakeFingerprintEngineUdfps::defaultSensorLocation() {
return {0 /* displayId (not used) */, defaultSensorLocationX /* sensorLocationX */,
defaultSensorLocationY /* sensorLocationY */, defaultSensorRadius /* sensorRadius */,
@@ -37,22 +43,95 @@
int32_t /*x*/, int32_t /*y*/,
float /*minor*/, float /*major*/) {
BEGIN_OP(0);
-
- // TODO(b/230515082): if need to handle display touch events
-
+ // verify whetehr touch coordinates/area matching sensor location ?
+ mPointerDownTime = Util::getSystemNanoTime();
+ if (FingerprintHalProperties::control_illumination().value_or(false)) {
+ fingerDownAction();
+ }
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus FakeFingerprintEngineUdfps::onPointerUpImpl(int32_t /*pointerId*/) {
BEGIN_OP(0);
- // TODO(b/230515082)
+ mUiReadyTime = 0;
+ mPointerDownTime = 0;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus FakeFingerprintEngineUdfps::onUiReadyImpl() {
BEGIN_OP(0);
- // TODO(b/230515082)
+
+ if (Util::hasElapsed(mPointerDownTime, uiReadyTimeoutInMs * 100)) {
+ LOG(ERROR) << "onUiReady() arrives too late after onPointerDown()";
+ } else {
+ fingerDownAction();
+ }
return ndk::ScopedAStatus::ok();
}
+void FakeFingerprintEngineUdfps::fingerDownAction() {
+ switch (mWorkMode) {
+ case WorkMode::kAuthenticate:
+ onAuthenticateFingerDown();
+ break;
+ case WorkMode::kEnroll:
+ onEnrollFingerDown();
+ break;
+ case WorkMode::kDetectInteract:
+ onDetectInteractFingerDown();
+ break;
+ default:
+ LOG(WARNING) << "unexpected call: onUiReady()";
+ break;
+ }
+
+ mUiReadyTime = 0;
+ mPointerDownTime = 0;
+}
+
+void FakeFingerprintEngineUdfps::onAuthenticateFingerDown() {
+ FakeFingerprintEngine::authenticateImpl(mCb, mOperationId, mCancelVec[0]);
+}
+
+void FakeFingerprintEngineUdfps::onEnrollFingerDown() {
+ // Any use case to emulate display touch for each capture during enrollment?
+ FakeFingerprintEngine::enrollImpl(mCb, mHat, mCancelVec[0]);
+}
+
+void FakeFingerprintEngineUdfps::onDetectInteractFingerDown() {
+ FakeFingerprintEngine::detectInteractionImpl(mCb, mCancelVec[0]);
+}
+
+void FakeFingerprintEngineUdfps::enrollImpl(ISessionCallback* cb,
+ const keymaster::HardwareAuthToken& hat,
+ const std::future<void>& cancel) {
+ updateContext(WorkMode::kEnroll, cb, const_cast<std::future<void>&>(cancel), 0, hat);
+}
+
+void FakeFingerprintEngineUdfps::authenticateImpl(ISessionCallback* cb, int64_t operationId,
+ const std::future<void>& cancel) {
+ updateContext(WorkMode::kAuthenticate, cb, const_cast<std::future<void>&>(cancel), operationId,
+ keymaster::HardwareAuthToken());
+}
+
+void FakeFingerprintEngineUdfps::detectInteractionImpl(ISessionCallback* cb,
+ const std::future<void>& cancel) {
+ updateContext(WorkMode::kDetectInteract, cb, const_cast<std::future<void>&>(cancel), 0,
+ keymaster::HardwareAuthToken());
+}
+
+void FakeFingerprintEngineUdfps::updateContext(WorkMode mode, ISessionCallback* cb,
+ std::future<void>& cancel, int64_t operationId,
+ const keymaster::HardwareAuthToken& hat) {
+ mPointerDownTime = 0;
+ mUiReadyTime = 0;
+ mCancelVec.clear();
+
+ mCancelVec.push_back(std::move(cancel));
+ mWorkMode = mode;
+ mCb = cb;
+ mOperationId = operationId;
+ mHat = hat;
+}
+
} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
new file mode 100644
index 0000000..5996406
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
@@ -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.
+ */
+
+#include "FakeLockoutTracker.h"
+#include <fingerprint.sysprop.h>
+#include "util/Util.h"
+
+using namespace ::android::fingerprint::virt;
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+void FakeLockoutTracker::reset() {
+ mFailedCount = 0;
+ mLockoutTimedStart = 0;
+ mCurrentMode = LockoutMode::kNone;
+}
+
+void FakeLockoutTracker::addFailedAttempt() {
+ bool enabled = FingerprintHalProperties::lockout_enable().value_or(false);
+ if (enabled) {
+ mFailedCount++;
+ int32_t lockoutTimedThreshold =
+ FingerprintHalProperties::lockout_timed_threshold().value_or(5);
+ int32_t lockoutPermanetThreshold =
+ FingerprintHalProperties::lockout_permanent_threshold().value_or(20);
+ if (mFailedCount >= lockoutPermanetThreshold) {
+ mCurrentMode = LockoutMode::kPermanent;
+ FingerprintHalProperties::lockout(true);
+ } else if (mFailedCount >= lockoutTimedThreshold) {
+ if (mCurrentMode == LockoutMode::kNone) {
+ mCurrentMode = LockoutMode::kTimed;
+ mLockoutTimedStart = Util::getSystemNanoTime();
+ }
+ }
+ } else {
+ reset();
+ }
+}
+
+FakeLockoutTracker::LockoutMode FakeLockoutTracker::getMode() {
+ if (mCurrentMode == LockoutMode::kTimed) {
+ int32_t lockoutTimedDuration =
+ FingerprintHalProperties::lockout_timed_duration().value_or(10 * 100);
+ if (Util::hasElapsed(mLockoutTimedStart, lockoutTimedDuration)) {
+ mCurrentMode = LockoutMode::kNone;
+ mLockoutTimedStart = 0;
+ }
+ }
+
+ return mCurrentMode;
+}
+
+int64_t FakeLockoutTracker::getLockoutTimeLeft() {
+ int64_t res = 0;
+
+ if (mLockoutTimedStart > 0) {
+ auto now = Util::getSystemNanoTime();
+ auto left = now - mLockoutTimedStart;
+ res = (left > 0) ? (left / 1000000LL) : 0;
+ }
+
+ return res;
+}
+} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
index 74e7caf..be93224 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -15,11 +15,13 @@
*/
#include "Fingerprint.h"
-
-#include <fingerprint.sysprop.h>
#include "Session.h"
+#include <fingerprint.sysprop.h>
+
+#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
using namespace ::android::fingerprint::virt;
@@ -64,7 +66,6 @@
{HW_COMPONENT_ID, HW_VERSION, FW_VERSION, SERIAL_NUMBER, "" /* softwareVersion */},
{SW_COMPONENT_ID, "" /* hardwareVersion */, "" /* firmwareVersion */,
"" /* serialNumber */, SW_VERSION}};
-
auto sensorId = FingerprintHalProperties::sensor_id().value_or(SENSOR_ID);
auto sensorStrength =
FingerprintHalProperties::sensor_strength().value_or((int)SENSOR_STRENGTH);
@@ -80,7 +81,8 @@
SensorLocation sensorLocation = mEngine->getSensorLocation();
- LOG(INFO) << "sensor type:" << (int)mSensorType << " location:" << sensorLocation.toString();
+ LOG(INFO) << "sensor type:" << ::android::internal::ToString(mSensorType)
+ << " location:" << sensorLocation.toString();
*out = {{commonProps,
mSensorType,
@@ -104,4 +106,96 @@
return ndk::ScopedAStatus::ok();
}
+binder_status_t Fingerprint::dump(int fd, const char** /*args*/, uint32_t numArgs) {
+ if (fd < 0) {
+ LOG(ERROR) << "Fingerprint::dump fd invalid: " << fd;
+ return STATUS_BAD_VALUE;
+ } else {
+ LOG(INFO) << "Fingerprint::dump fd:" << fd << "numArgs:" << numArgs;
+ }
+
+ dprintf(fd, "----- FingerprintVirtualHal::dump -----\n");
+ std::vector<SensorProps> sps(1);
+ getSensorProps(&sps);
+ for (auto& sp : sps) {
+ ::android::base::WriteStringToFd(sp.toString(), fd);
+ }
+ ::android::base::WriteStringToFd(mEngine->toString(), fd);
+
+ fsync(fd);
+ return STATUS_OK;
+}
+
+binder_status_t Fingerprint::handleShellCommand(int in, int out, int err, const char** args,
+ uint32_t numArgs) {
+ LOG(INFO) << "Fingerprint::handleShellCommand in:" << in << " out:" << out << " err:" << err
+ << " numArgs:" << numArgs;
+
+ if (numArgs == 0) {
+ LOG(INFO) << "Fingerprint::handleShellCommand: available commands";
+ onHelp(out);
+ return STATUS_OK;
+ }
+
+ for (auto&& str : std::vector<std::string_view>(args, args + numArgs)) {
+ std::string option = str.data();
+ if (option.find("clearconfig") != std::string::npos ||
+ option.find("resetconfig") != std::string::npos) {
+ resetConfigToDefault();
+ }
+ if (option.find("help") != std::string::npos) {
+ onHelp(out);
+ }
+ }
+
+ return STATUS_OK;
+}
+
+void Fingerprint::onHelp(int fd) {
+ dprintf(fd, "Virtual HAL commands:\n");
+ dprintf(fd, " help: print this help\n");
+ dprintf(fd, " resetconfig: reset all configuration to default\n");
+ dprintf(fd, "\n");
+ fsync(fd);
+}
+
+void Fingerprint::resetConfigToDefault() {
+ LOG(INFO) << "reset virtual HAL configuration to default";
+#define RESET_CONFIG_O(__NAME__) \
+ if (FingerprintHalProperties::__NAME__()) FingerprintHalProperties::__NAME__(std::nullopt)
+#define RESET_CONFIG_V(__NAME__) \
+ if (!FingerprintHalProperties::__NAME__().empty()) \
+ FingerprintHalProperties::__NAME__({std::nullopt})
+
+ RESET_CONFIG_O(type);
+ RESET_CONFIG_V(enrollments);
+ RESET_CONFIG_O(enrollment_hit);
+ RESET_CONFIG_O(authenticator_id);
+ RESET_CONFIG_O(challenge);
+ RESET_CONFIG_O(lockout);
+ RESET_CONFIG_O(operation_authenticate_fails);
+ RESET_CONFIG_O(operation_detect_interaction_error);
+ RESET_CONFIG_O(operation_enroll_error);
+ RESET_CONFIG_V(operation_authenticate_latency);
+ RESET_CONFIG_V(operation_detect_interaction_latency);
+ RESET_CONFIG_V(operation_enroll_latency);
+ RESET_CONFIG_O(operation_authenticate_duration);
+ RESET_CONFIG_O(operation_authenticate_error);
+ RESET_CONFIG_O(sensor_location);
+ RESET_CONFIG_O(operation_authenticate_acquired);
+ RESET_CONFIG_O(operation_detect_interaction_duration);
+ RESET_CONFIG_O(operation_detect_interaction_acquired);
+ RESET_CONFIG_O(sensor_id);
+ RESET_CONFIG_O(sensor_strength);
+ RESET_CONFIG_O(max_enrollments);
+ RESET_CONFIG_O(navigation_guesture);
+ RESET_CONFIG_O(detect_interaction);
+ RESET_CONFIG_O(display_touch);
+ RESET_CONFIG_O(control_illumination);
+ RESET_CONFIG_O(lockout_enable);
+ RESET_CONFIG_O(lockout_timed_threshold);
+ RESET_CONFIG_O(lockout_timed_duration);
+ RESET_CONFIG_O(lockout_permanent_threshold);
+}
+
} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/README.md b/biometrics/fingerprint/aidl/default/README.md
index ad471f7..49b6c9d 100644
--- a/biometrics/fingerprint/aidl/default/README.md
+++ b/biometrics/fingerprint/aidl/default/README.md
@@ -57,6 +57,7 @@
```shell
$ adb shell setprop vendor.fingerprint.virtual.next_enrollment 1:100,100,100:true
```
+
3. Navigate to `Settings -> Security -> Fingerprint Unlock` and follow the
prompts.
4. Verify the enrollments in the UI:
@@ -119,6 +120,38 @@
```
For vendor specific error, errorCode = 1000 + vendorErrorCode
+## Latency Insertion
+Three HAL operations (authenticate, enrollment and detect interaction) latency can be optionally specified in multiple ways
+1. default latency is fixed at 400 ms if not specified via sysprop
+2. specify authenticate operation latency to 900 ms
+ ```shell adb shell setprop vendor.fingerprint.virtual.operation_authenticate_latency 900```
+3. specify authenticate operation latency between 600 to 1200 ms in unifrom distribution
+ ```shelladb shell setprop vendor.fingerprint.virtual.operation_authenticate_latency 600,1200```
+
+## Lockout
+To force the device into lockout state
+```shell
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout true
+```
+To test permanent lockout based on the failed authentication attempts (e.g. 7)
+```shell
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout_permanent_threshold 7
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout_enable true
+```
+To test timed lockout based on the failed authentication attempts (e.g. 8 seconds on 5 attempts)
+```shell
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout_timed_duration 8000
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout_timed_threshold 5
+$ adb shell setprop persist.vendor.fingerprint.virtual.lockout_enable true
+```
+
+## Reset all configurations to default
+The following command will reset virtual configurations (related system properties) to default value.
+```shell
+$ adb shell cmd android.hardware.biometrics.fingerprint.IFingerprint/virtual resetconfig
+$ adb reboot
+```
+
## View HAL State
To view all the properties of the HAL (see `fingerprint.sysprop` file for the API):
@@ -126,3 +159,7 @@
```shell
$ adb shell getprop | grep vendor.fingerprint.virtual
```
+To dump virtual HAL internal data
+```shell
+adb shell dumpsys android.hardware.biometrics.fingerprint.IFingerprint/virtual
+```
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index e51f677..7ab5af3 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -20,6 +20,9 @@
#include "util/CancellationSignal.h"
+#undef LOG_TAG
+#define LOG_TAG "FingerprintVirtualHalSession"
+
namespace aidl::android::hardware::biometrics::fingerprint {
Session::Session(int sensorId, int userId, std::shared_ptr<ISessionCallback> cb,
diff --git a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
index fa21663..e69de29 100644
--- a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
+++ b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt
@@ -1,155 +0,0 @@
-props {
- owner: Vendor
- module: "android.fingerprint.virt.FingerprintHalProperties"
- prop {
- api_name: "authenticator_id"
- type: Long
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
- }
- prop {
- api_name: "challenge"
- type: Long
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.challenge"
- }
- prop {
- api_name: "control_illumination"
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
- }
- prop {
- api_name: "detect_interaction"
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
- }
- prop {
- api_name: "display_touch"
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
- }
- prop {
- api_name: "enrollment_hit"
- type: Integer
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.enrollment_hit"
- }
- prop {
- api_name: "enrollments"
- type: IntegerList
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.enrollments"
- }
- prop {
- api_name: "lockout"
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.lockout"
- }
- prop {
- api_name: "max_enrollments"
- type: Integer
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
- }
- prop {
- api_name: "navigation_guesture"
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
- }
- prop {
- api_name: "next_enrollment"
- type: String
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.next_enrollment"
- }
- prop {
- api_name: "operation_authenticate_acquired"
- type: String
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
- }
- prop {
- api_name: "operation_authenticate_duration"
- type: Integer
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
- }
- prop {
- api_name: "operation_authenticate_error"
- type: Integer
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
- }
- prop {
- api_name: "operation_authenticate_fails"
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
- }
- prop {
- api_name: "operation_authenticate_latency"
- type: Integer
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
- }
- prop {
- api_name: "operation_detect_interaction_acquired"
- type: String
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
- }
- prop {
- api_name: "operation_detect_interaction_duration"
- type: Integer
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
- }
- prop {
- api_name: "operation_detect_interaction_error"
- type: Integer
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
- }
- prop {
- api_name: "operation_detect_interaction_latency"
- type: Integer
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
- }
- prop {
- api_name: "operation_enroll_error"
- type: Integer
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
- }
- prop {
- api_name: "operation_enroll_latency"
- type: Integer
- access: ReadWrite
- prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
- }
- prop {
- api_name: "sensor_id"
- type: Integer
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
- }
- prop {
- api_name: "sensor_location"
- type: String
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
- }
- prop {
- api_name: "sensor_strength"
- type: Integer
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
- }
- prop {
- api_name: "type"
- type: String
- access: ReadWrite
- prop_name: "persist.vendor.fingerprint.virtual.type"
- enum_values: "default|rear|udfps|side"
- }
-}
diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.xml b/biometrics/fingerprint/aidl/default/fingerprint-example.xml
index 05d1279..e977b98 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint-example.xml
+++ b/biometrics/fingerprint/aidl/default/fingerprint-example.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.biometrics.fingerprint</name>
- <version>2</version>
+ <version>3</version>
<fqname>IFingerprint/virtual</fqname>
</hal>
</manifest>
diff --git a/biometrics/fingerprint/aidl/default/fingerprint.sysprop b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
index 9b8fada..6a6c297 100644
--- a/biometrics/fingerprint/aidl/default/fingerprint.sysprop
+++ b/biometrics/fingerprint/aidl/default/fingerprint.sysprop
@@ -7,7 +7,7 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.type"
type: String
- scope: Public
+ scope: Internal
access: ReadWrite
enum_values: "default|rear|udfps|side"
api_name: "type"
@@ -17,7 +17,7 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.enrollments"
type: IntegerList
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "enrollments"
}
@@ -27,7 +27,7 @@
prop {
prop_name: "vendor.fingerprint.virtual.enrollment_hit"
type: Integer
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "enrollment_hit"
}
@@ -42,7 +42,7 @@
prop {
prop_name: "vendor.fingerprint.virtual.next_enrollment"
type: String
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "next_enrollment"
}
@@ -51,7 +51,7 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
type: Long
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "authenticator_id"
}
@@ -60,25 +60,16 @@
prop {
prop_name: "vendor.fingerprint.virtual.challenge"
type: Long
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "challenge"
}
-# if locked out
-prop {
- prop_name: "persist.vendor.fingerprint.virtual.lockout"
- type: Boolean
- scope: Public
- access: ReadWrite
- api_name: "lockout"
-}
-
# force all authenticate operations to fail
prop {
prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails"
type: Boolean
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "operation_authenticate_fails"
}
@@ -91,7 +82,7 @@
prop {
prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
type: Integer
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "operation_detect_interaction_error"
}
@@ -100,34 +91,40 @@
prop {
prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
type: Integer
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "operation_enroll_error"
}
# add a latency to authentication operations
+# default to 400ms
+# [x] = x ms
+# [x,y] = randomly between x and y ms
+# others = invalid
prop {
prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
- type: Integer
- scope: Public
+ type: IntegerList
+ scope: Internal
access: ReadWrite
api_name: "operation_authenticate_latency"
}
# add a latency to detectInteraction operations
+# refer to `operation_authenticate_latency` above for usage
prop {
prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
- type: Integer
- scope: Public
+ type: IntegerList
+ scope: Internal
access: ReadWrite
api_name: "operation_detect_interaction_latency"
}
# add a latency to enroll operations
+# refer to `operation_authenticate_latency` above for usage
prop {
prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
- type: Integer
- scope: Public
+ type: IntegerList
+ scope: Internal
access: ReadWrite
api_name: "operation_enroll_latency"
}
@@ -137,7 +134,7 @@
prop {
prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
type: Integer
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "operation_authenticate_duration"
}
@@ -146,7 +143,7 @@
prop {
prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
type: Integer
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "operation_authenticate_error"
}
@@ -156,7 +153,7 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
type: String
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "sensor_location"
}
@@ -165,7 +162,7 @@
prop {
prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
type: String
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "operation_authenticate_acquired"
}
@@ -175,7 +172,7 @@
prop {
prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
type: Integer
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "operation_detect_interaction_duration"
}
@@ -187,7 +184,7 @@
prop {
prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
type: String
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "operation_detect_interaction_acquired"
}
@@ -196,7 +193,7 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
type: Integer
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "sensor_id"
}
@@ -206,7 +203,7 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
type: Integer
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "sensor_strength"
}
@@ -216,7 +213,7 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
type: Integer
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "max_enrollments"
}
@@ -225,7 +222,7 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
type: Boolean
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "navigation_guesture"
}
@@ -234,7 +231,7 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
type: Boolean
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "detect_interaction"
}
@@ -243,7 +240,7 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
type: Boolean
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "display_touch"
}
@@ -252,7 +249,52 @@
prop {
prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
type: Boolean
- scope: Public
+ scope: Internal
access: ReadWrite
api_name: "control_illumination"
}
+
+# force to be locked out (default: false)
+prop {
+ prop_name: "persist.vendor.fingerprint.virtual.lockout"
+ type: Boolean
+ scope: Internal
+ access: ReadWrite
+ api_name: "lockout"
+}
+
+# whether support lockout based on the failed auth attempts (default: false)
+prop {
+ prop_name: "persist.vendor.fingerprint.virtual.lockout_enable"
+ type: Boolean
+ scope: Internal
+ access: ReadWrite
+ api_name: "lockout_enable"
+}
+
+# temporarily lockout threshold in number of consecutive failed auth attempts (default: 5)
+prop {
+ prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_threshold"
+ type: Integer
+ scope: Internal
+ access: ReadWrite
+ api_name: "lockout_timed_threshold"
+}
+
+# temporary lockout duration in ms (default: 10000ms)
+prop {
+ prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_duration"
+ type: Integer
+ scope: Internal
+ access: ReadWrite
+ api_name: "lockout_timed_duration"
+}
+
+# permanently lockout threshold in number of consecutive failed auth attempts (default: 20)
+prop {
+ prop_name: "persist.vendor.fingerprint.virtual.lockout_permanent_threshold"
+ type: Integer
+ scope: Internal
+ access: ReadWrite
+ api_name: "lockout_permanent_threshold"
+}
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 22b1744..1279cd9 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -15,8 +15,13 @@
*/
#pragma once
+
+#define LOG_TAG "FingerprintVirtualHal"
+
#include <aidl/android/hardware/biometrics/common/SensorStrength.h>
#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
+#include <android/binder_to_string.h>
+#include <string>
#include <random>
@@ -24,6 +29,8 @@
#include <future>
#include <vector>
+#include "FakeLockoutTracker.h"
+
using namespace ::aidl::android::hardware::biometrics::common;
namespace aidl::android::hardware::biometrics::fingerprint {
@@ -36,11 +43,11 @@
void generateChallengeImpl(ISessionCallback* cb);
void revokeChallengeImpl(ISessionCallback* cb, int64_t challenge);
- void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
- const std::future<void>& cancel);
- void authenticateImpl(ISessionCallback* cb, int64_t operationId,
- const std::future<void>& cancel);
- void detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel);
+ virtual void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+ const std::future<void>& cancel);
+ virtual void authenticateImpl(ISessionCallback* cb, int64_t operationId,
+ const std::future<void>& cancel);
+ virtual void detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel);
void enumerateEnrollmentsImpl(ISessionCallback* cb);
void removeEnrollmentsImpl(ISessionCallback* cb, const std::vector<int32_t>& enrollmentIds);
void getAuthenticatorIdImpl(ISessionCallback* cb);
@@ -63,13 +70,29 @@
std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str);
+ int32_t getLatency(const std::vector<std::optional<std::int32_t>>& latencyVec);
+
std::mt19937 mRandom;
+ virtual std::string toString() const {
+ std::ostringstream os;
+ os << "----- FakeFingerprintEngine:: -----" << std::endl;
+ os << "acquiredVendorInfoBase:" << FINGERPRINT_ACQUIRED_VENDOR_BASE;
+ os << ", errorVendorBase:" << FINGERPRINT_ERROR_VENDOR_BASE << std::endl;
+ os << mLockoutTracker.toString();
+ return os.str();
+ }
+
private:
static constexpr int32_t FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
static constexpr int32_t FINGERPRINT_ERROR_VENDOR_BASE = 1000;
std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
std::pair<Error, int32_t> convertError(int32_t code);
+ bool parseEnrollmentCaptureSingle(const std::string& str,
+ std::vector<std::vector<int32_t>>& res);
+ int32_t getRandomInRange(int32_t bound1, int32_t bound2);
+
+ FakeLockoutTracker mLockoutTracker;
};
} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineRear.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineRear.h
index 1600a4b..14d5399 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineRear.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineRear.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h
index 4e44d16..c2fc005 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineSide.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h
index b86af73..c5e93e7 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngineUdfps.h
@@ -28,17 +28,55 @@
static constexpr int32_t defaultSensorLocationY = 1600;
static constexpr int32_t defaultSensorRadius = 150;
- FakeFingerprintEngineUdfps() : FakeFingerprintEngine() {}
+ static constexpr int32_t uiReadyTimeoutInMs = 5000;
+
+ FakeFingerprintEngineUdfps();
~FakeFingerprintEngineUdfps() {}
- virtual ndk::ScopedAStatus onPointerDownImpl(int32_t pointerId, int32_t x, int32_t y,
- float minor, float major) override;
+ ndk::ScopedAStatus onPointerDownImpl(int32_t pointerId, int32_t x, int32_t y, float minor,
+ float major) override;
- virtual ndk::ScopedAStatus onPointerUpImpl(int32_t pointerId) override;
+ ndk::ScopedAStatus onPointerUpImpl(int32_t pointerId) override;
- virtual ndk::ScopedAStatus onUiReadyImpl() override;
+ ndk::ScopedAStatus onUiReadyImpl() override;
- virtual SensorLocation defaultSensorLocation() override;
+ SensorLocation defaultSensorLocation() override;
+
+ void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+ const std::future<void>& cancel);
+ void authenticateImpl(ISessionCallback* cb, int64_t operationId,
+ const std::future<void>& cancel);
+ void detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel);
+
+ enum class WorkMode : int8_t { kIdle = 0, kAuthenticate, kEnroll, kDetectInteract };
+
+ WorkMode getWorkMode() { return mWorkMode; }
+
+ std::string toString() const {
+ std::ostringstream os;
+ os << FakeFingerprintEngine::toString();
+ os << "----- FakeFingerprintEngineUdfps -----" << std::endl;
+ os << "mWorkMode:" << (int)mWorkMode;
+ os << ", mUiReadyTime:" << mUiReadyTime;
+ os << ", mPointerDownTime:" << mPointerDownTime << std::endl;
+ return os.str();
+ }
+
+ private:
+ void onAuthenticateFingerDown();
+ void onEnrollFingerDown();
+ void onDetectInteractFingerDown();
+ void fingerDownAction();
+ void updateContext(WorkMode mode, ISessionCallback* cb, std::future<void>& cancel,
+ int64_t operationId, const keymaster::HardwareAuthToken& hat);
+
+ WorkMode mWorkMode;
+ ISessionCallback* mCb;
+ keymaster::HardwareAuthToken mHat;
+ std::vector<std::future<void>> mCancelVec;
+ int64_t mOperationId;
+ int64_t mPointerDownTime;
+ int64_t mUiReadyTime;
};
} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h b/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h
new file mode 100644
index 0000000..a1b6128
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h
@@ -0,0 +1,51 @@
+/*
+ * 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/binder_to_string.h>
+#include <stdint.h>
+#include <string>
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+class FakeLockoutTracker {
+ public:
+ FakeLockoutTracker() : mFailedCount(0) {}
+ ~FakeLockoutTracker() {}
+
+ enum class LockoutMode : int8_t { kNone = 0, kTimed, kPermanent };
+
+ void reset();
+ LockoutMode getMode();
+ void addFailedAttempt();
+ int64_t getLockoutTimeLeft();
+ inline std::string toString() const {
+ std::ostringstream os;
+ os << "----- FakeLockoutTracker:: -----" << std::endl;
+ os << "FakeLockoutTracker::mFailedCount:" << mFailedCount;
+ os << ", FakeLockoutTracker::mCurrentMode:" << (int)mCurrentMode;
+ os << std::endl;
+ return os.str();
+ }
+
+ private:
+ int32_t mFailedCount;
+ int64_t mLockoutTimedStart;
+ LockoutMode mCurrentMode;
+};
+
+} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/Fingerprint.h b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
index 64aafa3..fc4fb8d 100644
--- a/biometrics/fingerprint/aidl/default/include/Fingerprint.h
+++ b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
@@ -16,8 +16,6 @@
#pragma once
-#define LOG_TAG "FingerprintVirtualHal"
-
#include <aidl/android/hardware/biometrics/fingerprint/BnFingerprint.h>
#include "FakeFingerprintEngine.h"
@@ -39,8 +37,13 @@
ndk::ScopedAStatus createSession(int32_t sensorId, int32_t userId,
const std::shared_ptr<ISessionCallback>& cb,
std::shared_ptr<ISession>* out) override;
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs);
+ binder_status_t handleShellCommand(int in, int out, int err, const char** argv, uint32_t argc);
private:
+ void resetConfigToDefault();
+ void onHelp(int);
+
std::unique_ptr<FakeFingerprintEngine> mEngine;
WorkerThread mWorker;
std::shared_ptr<Session> mSession;
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
index 32d01f4..a200b39 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -21,6 +21,7 @@
#include <aidl/android/hardware/biometrics/fingerprint/BnSessionCallback.h>
#include "FakeFingerprintEngine.h"
+#include "util/Util.h"
using namespace ::android::fingerprint::virt;
using namespace ::aidl::android::hardware::biometrics::fingerprint;
@@ -118,9 +119,9 @@
class FakeFingerprintEngineTest : public ::testing::Test {
protected:
void SetUp() override {
- FingerprintHalProperties::operation_enroll_latency(0);
- FingerprintHalProperties::operation_authenticate_latency(0);
- FingerprintHalProperties::operation_detect_interaction_latency(0);
+ FingerprintHalProperties::operation_enroll_latency({0});
+ FingerprintHalProperties::operation_authenticate_latency({0});
+ FingerprintHalProperties::operation_detect_interaction_latency({0});
mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
}
@@ -128,6 +129,9 @@
FingerprintHalProperties::operation_authenticate_error(0);
FingerprintHalProperties::operation_detect_interaction_error(0);
FingerprintHalProperties::operation_authenticate_acquired("");
+ FingerprintHalProperties::operation_enroll_latency({});
+ FingerprintHalProperties::operation_authenticate_latency({});
+ FingerprintHalProperties::operation_detect_interaction_latency({});
}
FakeFingerprintEngine mEngine;
@@ -291,6 +295,7 @@
}
TEST_F(FakeFingerprintEngineTest, InteractionDetect) {
+ FingerprintHalProperties::detect_interaction(true);
FingerprintHalProperties::enrollments({1, 2});
FingerprintHalProperties::enrollment_hit(2);
FingerprintHalProperties::operation_detect_interaction_acquired("");
@@ -300,6 +305,7 @@
}
TEST_F(FakeFingerprintEngineTest, InteractionDetectCancel) {
+ FingerprintHalProperties::detect_interaction(true);
FingerprintHalProperties::enrollments({1, 2});
FingerprintHalProperties::enrollment_hit(2);
mCancel.set_value();
@@ -309,6 +315,7 @@
}
TEST_F(FakeFingerprintEngineTest, InteractionDetectNotSet) {
+ FingerprintHalProperties::detect_interaction(true);
FingerprintHalProperties::enrollments({1, 2});
FingerprintHalProperties::enrollment_hit({});
mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
@@ -323,6 +330,7 @@
}
TEST_F(FakeFingerprintEngineTest, InteractionDetectError) {
+ FingerprintHalProperties::detect_interaction(true);
FingerprintHalProperties::operation_detect_interaction_error(8);
mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
@@ -331,6 +339,7 @@
}
TEST_F(FakeFingerprintEngineTest, InteractionDetectAcquired) {
+ FingerprintHalProperties::detect_interaction(true);
FingerprintHalProperties::enrollments({1, 2});
FingerprintHalProperties::enrollment_hit(2);
FingerprintHalProperties::operation_detect_interaction_acquired("4,1013");
@@ -435,12 +444,29 @@
std::vector<std::string> badStr{"10c", "100-5", "100-[5,6,7", "100-5,6,7]",
"100,2x0,300", "200-[f]", "a,b"};
std::vector<std::vector<int32_t>> ecV;
- for (const auto s : badStr) {
+ for (const auto& s : badStr) {
ecV = mEngine.parseEnrollmentCapture(s);
ASSERT_EQ(ecV.size(), 0);
}
}
+TEST_F(FakeFingerprintEngineTest, randomLatency) {
+ FingerprintHalProperties::operation_detect_interaction_latency({});
+ ASSERT_EQ(DEFAULT_LATENCY,
+ mEngine.getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
+ FingerprintHalProperties::operation_detect_interaction_latency({10});
+ ASSERT_EQ(10,
+ mEngine.getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
+ FingerprintHalProperties::operation_detect_interaction_latency({1, 1000});
+ std::set<int32_t> latencySet;
+ for (int i = 0; i < 100; i++) {
+ latencySet.insert(mEngine.getLatency(
+ FingerprintHalProperties::operation_detect_interaction_latency()));
+ }
+ ASSERT_TRUE(latencySet.size() > 95);
+ FingerprintHalProperties::operation_detect_interaction_latency({});
+}
+
} // namespace aidl::android::hardware::biometrics::fingerprint
int main(int argc, char** argv) {
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
index 7c0021f..f551899 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <aidl/android/hardware/biometrics/fingerprint/BnSessionCallback.h>
#include <android/binder_process.h>
#include <fingerprint.sysprop.h>
#include <gtest/gtest.h>
@@ -29,6 +30,69 @@
namespace aidl::android::hardware::biometrics::fingerprint {
+class TestSessionCallback : public BnSessionCallback {
+ public:
+ ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override {
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onError(fingerprint::Error /*error*/, int32_t /*vendorCode*/) override {
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/,
+ int32_t /*remaining*/) override {
+ mEnrollmentProgress++;
+ return ndk::ScopedAStatus::ok();
+ };
+
+ ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t /*enrollmentId*/,
+ const keymaster::HardwareAuthToken&) override {
+ mAuthenticationSuccess++;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onAuthenticationFailed() override {
+ mAuthenticationFailure++;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onInteractionDetected() override {
+ mDetectInteraction++;
+ return ndk::ScopedAStatus::ok();
+ };
+ ndk::ScopedAStatus onAcquired(AcquiredInfo /*info*/, int32_t /*vendorCode*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onEnrollmentsEnumerated(
+ const std::vector<int32_t>& /*enrollmentIds*/) override {
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onEnrollmentsRemoved(
+ const std::vector<int32_t>& /*enrollmentIds*/) override {
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*authenticatorId*/) override {
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onLockoutPermanent() override { return ndk::ScopedAStatus::ok(); };
+ ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus onLockoutCleared() override { return ndk::ScopedAStatus::ok(); }
+ ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
+
+ int32_t getAuthenticationCount() { return mAuthenticationSuccess + mAuthenticationFailure; }
+ int32_t getDetectInteractionCount() { return mDetectInteraction; }
+
+ int32_t mAuthenticationSuccess = 0;
+ int32_t mAuthenticationFailure = 0;
+ int32_t mEnrollmentProgress = 0;
+ int32_t mDetectInteraction = 0;
+};
+
class FakeFingerprintEngineUdfpsTest : public ::testing::Test {
protected:
void SetUp() override {}
@@ -65,30 +129,56 @@
}
TEST_F(FakeFingerprintEngineUdfpsTest, getSensorLocationBad) {
- FingerprintHalProperties::sensor_location("");
- SensorLocation sc = mEngine.getSensorLocation();
- ASSERT_TRUE(isDefaultLocation(sc));
-
- auto loc = "100";
- FingerprintHalProperties::sensor_location(loc);
- sc = mEngine.getSensorLocation();
- ASSERT_TRUE(isDefaultLocation(sc));
-
- loc = "10:20";
- FingerprintHalProperties::sensor_location(loc);
- sc = mEngine.getSensorLocation();
- ASSERT_TRUE(isDefaultLocation(sc));
-
- loc = "10,20,5";
- FingerprintHalProperties::sensor_location(loc);
- sc = mEngine.getSensorLocation();
- ASSERT_TRUE(isDefaultLocation(sc));
-
- loc = "a:b:c";
- FingerprintHalProperties::sensor_location(loc);
- sc = mEngine.getSensorLocation();
- ASSERT_TRUE(isDefaultLocation(sc));
+ const std::vector<std::string> badStr{"", "100", "10:20", "10,20,5", "a:b:c"};
+ SensorLocation sc;
+ for (const auto& s : badStr) {
+ FingerprintHalProperties::sensor_location(s);
+ sc = mEngine.getSensorLocation();
+ ASSERT_TRUE(isDefaultLocation(sc));
+ }
}
+TEST_F(FakeFingerprintEngineUdfpsTest, initialization) {
+ ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kIdle);
+}
+
+TEST_F(FakeFingerprintEngineUdfpsTest, authenticate) {
+ std::shared_ptr<TestSessionCallback> cb = ndk::SharedRefBase::make<TestSessionCallback>();
+ std::promise<void> cancel;
+ mEngine.authenticateImpl(cb.get(), 1, cancel.get_future());
+ ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kAuthenticate);
+ mEngine.onPointerDownImpl(1, 2, 3, 4.0, 5.0);
+ ASSERT_EQ(cb->getAuthenticationCount(), 0);
+ mEngine.onUiReadyImpl();
+ ASSERT_EQ(cb->getAuthenticationCount(), 1);
+}
+
+TEST_F(FakeFingerprintEngineUdfpsTest, enroll) {
+ std::shared_ptr<TestSessionCallback> cb = ndk::SharedRefBase::make<TestSessionCallback>();
+ std::promise<void> cancel;
+ keymaster::HardwareAuthToken hat{.mac = {5, 6}};
+ FingerprintHalProperties::next_enrollment("5:0,0:true");
+ mEngine.enrollImpl(cb.get(), hat, cancel.get_future());
+ ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kEnroll);
+ mEngine.onPointerDownImpl(1, 2, 3, 4.0, 5.0);
+ ASSERT_EQ(cb->mEnrollmentProgress, 0);
+ mEngine.onUiReadyImpl();
+ ASSERT_TRUE(cb->mEnrollmentProgress > 0);
+}
+
+TEST_F(FakeFingerprintEngineUdfpsTest, detectInteraction) {
+ FingerprintHalProperties::detect_interaction(true);
+ FingerprintHalProperties::enrollments({1, 2});
+ FingerprintHalProperties::enrollment_hit(2);
+ FingerprintHalProperties::operation_detect_interaction_acquired("");
+ std::shared_ptr<TestSessionCallback> cb = ndk::SharedRefBase::make<TestSessionCallback>();
+ std::promise<void> cancel;
+ mEngine.detectInteractionImpl(cb.get(), cancel.get_future());
+ ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kDetectInteract);
+ mEngine.onPointerDownImpl(1, 2, 3, 4.0, 5.0);
+ ASSERT_EQ(cb->getDetectInteractionCount(), 0);
+ mEngine.onUiReadyImpl();
+ ASSERT_EQ(cb->getDetectInteractionCount(), 1);
+}
// More
} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
new file mode 100644
index 0000000..1b071ee
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 <android/binder_process.h>
+#include <fingerprint.sysprop.h>
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+#include "FakeLockoutTracker.h"
+#include "util/Util.h"
+
+using namespace ::android::fingerprint::virt;
+using namespace ::aidl::android::hardware::biometrics::fingerprint;
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+class FakeLockoutTrackerTest : public ::testing::Test {
+ protected:
+ static constexpr int32_t LOCKOUT_TIMED_THRESHOLD = 3;
+ static constexpr int32_t LOCKOUT_PERMANENT_THRESHOLD = 5;
+ static constexpr int32_t LOCKOUT_TIMED_DURATION = 100;
+
+ void SetUp() override {
+ FingerprintHalProperties::lockout_timed_threshold(LOCKOUT_TIMED_THRESHOLD);
+ FingerprintHalProperties::lockout_timed_duration(LOCKOUT_TIMED_DURATION);
+ FingerprintHalProperties::lockout_permanent_threshold(LOCKOUT_PERMANENT_THRESHOLD);
+ }
+
+ void TearDown() override {
+ // reset to default
+ FingerprintHalProperties::lockout_timed_threshold(5);
+ FingerprintHalProperties::lockout_timed_duration(20);
+ FingerprintHalProperties::lockout_permanent_threshold(10000);
+ FingerprintHalProperties::lockout_enable(false);
+ FingerprintHalProperties::lockout(false);
+ }
+
+ FakeLockoutTracker mLockoutTracker;
+};
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) {
+ FingerprintHalProperties::lockout_enable(false);
+ for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++) mLockoutTracker.addFailedAttempt();
+ ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
+ mLockoutTracker.reset();
+}
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
+ FingerprintHalProperties::lockout_enable(true);
+ for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++) mLockoutTracker.addFailedAttempt();
+ ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
+ // time left
+ int N = 5;
+ int64_t prevTimeLeft = INT_MIN;
+ for (int i = 0; i < N; i++) {
+ SLEEP_MS(LOCKOUT_TIMED_DURATION / N + 1);
+ int64_t currTimeLeft = mLockoutTracker.getLockoutTimeLeft();
+ ASSERT_TRUE(currTimeLeft > prevTimeLeft);
+ prevTimeLeft = currTimeLeft;
+ }
+ ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
+ mLockoutTracker.reset();
+}
+
+TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
+ FingerprintHalProperties::lockout_enable(true);
+ for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++) mLockoutTracker.addFailedAttempt();
+ ASSERT_NE(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
+ mLockoutTracker.addFailedAttempt();
+ ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
+ ASSERT_TRUE(FingerprintHalProperties::lockout());
+ mLockoutTracker.reset();
+}
+
+} // namespace aidl::android::hardware::biometrics::fingerprint
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/biometrics/fingerprint/aidl/vts/Android.bp b/biometrics/fingerprint/aidl/vts/Android.bp
index a474f66..1652905 100644
--- a/biometrics/fingerprint/aidl/vts/Android.bp
+++ b/biometrics/fingerprint/aidl/vts/Android.bp
@@ -15,9 +15,9 @@
],
srcs: ["VtsHalBiometricsFingerprintTargetTest.cpp"],
static_libs: [
- "android.hardware.biometrics.common-V2-ndk",
- "android.hardware.biometrics.fingerprint-V2-ndk",
- "android.hardware.keymaster-V3-ndk",
+ "android.hardware.biometrics.common-V3-ndk",
+ "android.hardware.biometrics.fingerprint-V3-ndk",
+ "android.hardware.keymaster-V4-ndk",
],
shared_libs: [
"libbinder_ndk",
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 674dd11..70797a7 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -63,6 +63,31 @@
generated_headers: ["le_audio_codec_capabilities"],
}
+cc_test {
+ name: "BluetoothLeAudioCodecsProviderTest",
+ srcs: [
+ "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
+ "aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
+ ],
+ header_libs: [
+ "libxsdc-utils",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.bluetooth.audio-V2-ndk",
+ "libxml2",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+ test_options: {
+ unit_test: false,
+ },
+ generated_sources: ["le_audio_codec_capabilities"],
+ generated_headers: ["le_audio_codec_capabilities"],
+}
+
xsd_config {
name: "le_audio_codec_capabilities",
srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"],
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index 855dd28..faebbbf 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -398,8 +398,11 @@
}
if (kDefaultOffloadLeAudioCapabilities.empty()) {
+ auto le_audio_offload_setting =
+ BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile();
kDefaultOffloadLeAudioCapabilities =
- BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities();
+ BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+ le_audio_offload_setting);
}
return kDefaultOffloadLeAudioCapabilities;
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
index bf49270..1dec900 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -34,20 +34,40 @@
static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
-std::vector<LeAudioCodecCapabilitiesSetting>
-BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {
- if (!leAudioCodecCapabilities.empty()) {
- return leAudioCodecCapabilities;
- }
+static bool isInvalidFileContent = false;
- const auto le_audio_offload_setting =
+std::optional<setting::LeAudioOffloadSetting>
+BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() {
+ if (!leAudioCodecCapabilities.empty() || isInvalidFileContent) {
+ return std::nullopt;
+ }
+ auto le_audio_offload_setting =
setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
if (!le_audio_offload_setting.has_value()) {
LOG(ERROR) << __func__ << ": Failed to read "
<< kLeAudioCodecCapabilitiesFile;
+ }
+ return le_audio_offload_setting;
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting) {
+ if (!leAudioCodecCapabilities.empty()) {
+ return leAudioCodecCapabilities;
+ }
+
+ if (!le_audio_offload_setting.has_value()) {
+ LOG(ERROR)
+ << __func__
+ << ": input le_audio_offload_setting content need to be non empty";
return {};
}
+ ClearLeAudioCodecCapabilities();
+ isInvalidFileContent = true;
+
std::vector<setting::Scenario> supported_scenarios =
GetScenarios(le_audio_offload_setting);
if (supported_scenarios.empty()) {
@@ -79,9 +99,18 @@
leAudioCodecCapabilities =
ComposeLeAudioCodecCapabilities(supported_scenarios);
+ isInvalidFileContent = leAudioCodecCapabilities.empty();
+
return leAudioCodecCapabilities;
}
+void BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities() {
+ leAudioCodecCapabilities.clear();
+ configuration_map_.clear();
+ codec_configuration_map_.clear();
+ strategy_configuration_map_.clear();
+}
+
std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
const std::optional<setting::LeAudioOffloadSetting>&
le_audio_offload_setting) {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
index 402235f..e879984 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -31,8 +31,13 @@
class BluetoothLeAudioCodecsProvider {
public:
+ static std::optional<setting::LeAudioOffloadSetting>
+ ParseFromLeAudioOffloadSettingFile();
static std::vector<LeAudioCodecCapabilitiesSetting>
- GetLeAudioCodecCapabilities();
+ GetLeAudioCodecCapabilities(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting);
+ static void ClearLeAudioCodecCapabilities();
private:
static inline std::unordered_map<std::string, setting::Configuration>
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
new file mode 100644
index 0000000..5393cd7
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
@@ -0,0 +1,373 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <optional>
+#include <tuple>
+
+#include "BluetoothLeAudioCodecsProvider.h"
+
+using aidl::android::hardware::bluetooth::audio::BluetoothLeAudioCodecsProvider;
+using aidl::android::hardware::bluetooth::audio::
+ LeAudioCodecCapabilitiesSetting;
+using aidl::android::hardware::bluetooth::audio::setting::AudioLocation;
+using aidl::android::hardware::bluetooth::audio::setting::CodecConfiguration;
+using aidl::android::hardware::bluetooth::audio::setting::
+ CodecConfigurationList;
+using aidl::android::hardware::bluetooth::audio::setting::CodecType;
+using aidl::android::hardware::bluetooth::audio::setting::Configuration;
+using aidl::android::hardware::bluetooth::audio::setting::ConfigurationList;
+using aidl::android::hardware::bluetooth::audio::setting::LeAudioOffloadSetting;
+using aidl::android::hardware::bluetooth::audio::setting::Scenario;
+using aidl::android::hardware::bluetooth::audio::setting::ScenarioList;
+using aidl::android::hardware::bluetooth::audio::setting::StrategyConfiguration;
+using aidl::android::hardware::bluetooth::audio::setting::
+ StrategyConfigurationList;
+
+typedef std::tuple<std::vector<ScenarioList>, std::vector<ConfigurationList>,
+ std::vector<CodecConfigurationList>,
+ std::vector<StrategyConfigurationList>>
+ OffloadSetting;
+
+// Define valid components for each list
+// Scenario
+static const Scenario kValidScenario(std::make_optional("OneChanStereo_16_1"),
+ std::make_optional("OneChanStereo_16_1"));
+// Configuration
+static const Configuration kValidConfigOneChanStereo_16_1(
+ std::make_optional("OneChanStereo_16_1"), std::make_optional("LC3_16k_1"),
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"));
+// CodecConfiguration
+static const CodecConfiguration kValidCodecLC3_16k_1(
+ std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+ std::nullopt, std::make_optional(16000), std::make_optional(7500),
+ std::make_optional(30), std::nullopt);
+// StrategyConfiguration
+static const StrategyConfiguration kValidStrategyStereoOneCis(
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+ std::make_optional(1));
+static const StrategyConfiguration kValidStrategyStereoTwoCis(
+ std::make_optional("STEREO_TWO_CISES_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO), std::make_optional(1),
+ std::make_optional(2));
+static const StrategyConfiguration kValidStrategyMonoOneCis(
+ std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::MONO), std::make_optional(1),
+ std::make_optional(1));
+
+// Define valid test list built from above valid components
+// Scenario, Configuration, CodecConfiguration, StrategyConfiguration
+static const std::vector<ScenarioList> kValidScenarioList = {
+ ScenarioList(std::vector<Scenario>{kValidScenario})};
+static const std::vector<ConfigurationList> kValidConfigurationList = {
+ ConfigurationList(
+ std::vector<Configuration>{kValidConfigOneChanStereo_16_1})};
+static const std::vector<CodecConfigurationList> kValidCodecConfigurationList =
+ {CodecConfigurationList(
+ std::vector<CodecConfiguration>{kValidCodecLC3_16k_1})};
+static const std::vector<StrategyConfigurationList>
+ kValidStrategyConfigurationList = {
+ StrategyConfigurationList(std::vector<StrategyConfiguration>{
+ kValidStrategyStereoOneCis, kValidStrategyStereoTwoCis,
+ kValidStrategyMonoOneCis})};
+
+class BluetoothLeAudioCodecsProviderTest
+ : public ::testing::TestWithParam<OffloadSetting> {
+ public:
+ static std::vector<OffloadSetting> CreateTestCases(
+ const std::vector<ScenarioList>& scenario_lists,
+ const std::vector<ConfigurationList>& configuration_lists,
+ const std::vector<CodecConfigurationList>& codec_configuration_lists,
+ const std::vector<StrategyConfigurationList>&
+ strategy_configuration_lists) {
+ // make each vector in output test_cases has only one element
+ // to match the input of test params
+ // normally only one vector in input has multiple elements
+ // we just split elements in this vector to several vector
+ std::vector<OffloadSetting> test_cases;
+ for (const auto& scenario_list : scenario_lists) {
+ for (const auto& configuration_list : configuration_lists) {
+ for (const auto& codec_configuration_list : codec_configuration_lists) {
+ for (const auto& strategy_configuration_list :
+ strategy_configuration_lists) {
+ test_cases.push_back(CreateTestCase(
+ scenario_list, configuration_list, codec_configuration_list,
+ strategy_configuration_list));
+ }
+ }
+ }
+ }
+ return test_cases;
+ }
+
+ protected:
+ void Initialize() {
+ BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities();
+ }
+
+ std::vector<LeAudioCodecCapabilitiesSetting> RunTestCase() {
+ auto& [scenario_lists, configuration_lists, codec_configuration_lists,
+ strategy_configuration_lists] = GetParam();
+ LeAudioOffloadSetting le_audio_offload_setting(
+ scenario_lists, configuration_lists, codec_configuration_lists,
+ strategy_configuration_lists);
+ auto le_audio_codec_capabilities =
+ BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+ std::make_optional(le_audio_offload_setting));
+ return le_audio_codec_capabilities;
+ }
+
+ private:
+ static inline OffloadSetting CreateTestCase(
+ const ScenarioList& scenario_list,
+ const ConfigurationList& configuration_list,
+ const CodecConfigurationList& codec_configuration_list,
+ const StrategyConfigurationList& strategy_configuration_list) {
+ return std::make_tuple(
+ std::vector<ScenarioList>{scenario_list},
+ std::vector<ConfigurationList>{configuration_list},
+ std::vector<CodecConfigurationList>{codec_configuration_list},
+ std::vector<StrategyConfigurationList>{strategy_configuration_list});
+ }
+};
+
+class GetScenariosTest : public BluetoothLeAudioCodecsProviderTest {
+ public:
+ static std::vector<ScenarioList> CreateInvalidScenarios() {
+ std::vector<ScenarioList> invalid_scenario_test_cases;
+ invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
+ Scenario(std::nullopt, std::make_optional("OneChanStereo_16_1"))}));
+
+ invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
+ Scenario(std::make_optional("OneChanStereo_16_1"), std::nullopt)}));
+
+ invalid_scenario_test_cases.push_back(ScenarioList(
+ std::vector<Scenario>{Scenario(std::nullopt, std::nullopt)}));
+
+ invalid_scenario_test_cases.push_back(
+ ScenarioList(std::vector<Scenario>{}));
+
+ return invalid_scenario_test_cases;
+ }
+};
+
+TEST_P(GetScenariosTest, InvalidScenarios) {
+ Initialize();
+ auto le_audio_codec_capabilities = RunTestCase();
+ ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateConfigurationsToMapTest
+ : public BluetoothLeAudioCodecsProviderTest {
+ public:
+ static std::vector<ConfigurationList> CreateInvalidConfigurations() {
+ std::vector<ConfigurationList> invalid_configuration_test_cases;
+ invalid_configuration_test_cases.push_back(
+ ConfigurationList(std::vector<Configuration>{
+ Configuration(std::nullopt, std::make_optional("LC3_16k_1"),
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))}));
+
+ invalid_configuration_test_cases.push_back(
+ ConfigurationList(std::vector<Configuration>{Configuration(
+ std::make_optional("OneChanStereo_16_1"), std::nullopt,
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))}));
+
+ invalid_configuration_test_cases.push_back(
+ ConfigurationList(std::vector<Configuration>{
+ Configuration(std::make_optional("OneChanStereo_16_1"),
+ std::make_optional("LC3_16k_1"), std::nullopt)}));
+
+ invalid_configuration_test_cases.push_back(
+ ConfigurationList(std::vector<Configuration>{}));
+
+ return invalid_configuration_test_cases;
+ }
+};
+
+TEST_P(UpdateConfigurationsToMapTest, InvalidConfigurations) {
+ Initialize();
+ auto le_audio_codec_capabilities = RunTestCase();
+ ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateCodecConfigurationsToMapTest
+ : public BluetoothLeAudioCodecsProviderTest {
+ public:
+ static std::vector<CodecConfigurationList>
+ CreateInvalidCodecConfigurations() {
+ std::vector<CodecConfigurationList> invalid_codec_configuration_test_cases;
+ invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+ std::vector<CodecConfiguration>{CodecConfiguration(
+ std::nullopt, std::make_optional(CodecType::LC3), std::nullopt,
+ std::make_optional(16000), std::make_optional(7500),
+ std::make_optional(30), std::nullopt)}));
+
+ invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+ std::vector<CodecConfiguration>{CodecConfiguration(
+ std::make_optional("LC3_16k_1"), std::nullopt, std::nullopt,
+ std::make_optional(16000), std::make_optional(7500),
+ std::make_optional(30), std::nullopt)}));
+
+ invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+ std::vector<CodecConfiguration>{CodecConfiguration(
+ std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+ std::nullopt, std::nullopt, std::make_optional(7500),
+ std::make_optional(30), std::nullopt)}));
+
+ invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+ std::vector<CodecConfiguration>{CodecConfiguration(
+ std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+ std::nullopt, std::make_optional(16000), std::nullopt,
+ std::make_optional(30), std::nullopt)}));
+
+ invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+ std::vector<CodecConfiguration>{CodecConfiguration(
+ std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+ std::nullopt, std::make_optional(16000), std::make_optional(7500),
+ std::nullopt, std::nullopt)}));
+
+ invalid_codec_configuration_test_cases.push_back(
+ CodecConfigurationList(std::vector<CodecConfiguration>{}));
+
+ return invalid_codec_configuration_test_cases;
+ }
+};
+
+TEST_P(UpdateCodecConfigurationsToMapTest, InvalidCodecConfigurations) {
+ Initialize();
+ auto le_audio_codec_capabilities = RunTestCase();
+ ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateStrategyConfigurationsToMapTest
+ : public BluetoothLeAudioCodecsProviderTest {
+ public:
+ static std::vector<StrategyConfigurationList>
+ CreateInvalidStrategyConfigurations() {
+ std::vector<StrategyConfigurationList>
+ invalid_strategy_configuration_test_cases;
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO),
+ std::make_optional(2), std::make_optional(2))}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO),
+ std::make_optional(2), std::make_optional(2))}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::nullopt, std::make_optional(AudioLocation::STEREO),
+ std::make_optional(2), std::make_optional(1))}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
+ std::make_optional(2), std::make_optional(1))}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO), std::nullopt,
+ std::make_optional(1))}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO),
+ std::make_optional(2), std::nullopt)}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(std::vector<StrategyConfiguration>{}));
+
+ return invalid_strategy_configuration_test_cases;
+ }
+};
+
+TEST_P(UpdateStrategyConfigurationsToMapTest, InvalidStrategyConfigurations) {
+ Initialize();
+ auto le_audio_codec_capabilities = RunTestCase();
+ ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class ComposeLeAudioCodecCapabilitiesTest
+ : public BluetoothLeAudioCodecsProviderTest {
+ public:
+};
+
+TEST_P(ComposeLeAudioCodecCapabilitiesTest, CodecCapabilitiesNotEmpty) {
+ Initialize();
+ auto le_audio_codec_capabilities = RunTestCase();
+ ASSERT_TRUE(!le_audio_codec_capabilities.empty());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GetScenariosTest);
+INSTANTIATE_TEST_SUITE_P(
+ BluetoothLeAudioCodecsProviderTest, GetScenariosTest,
+ ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+ GetScenariosTest::CreateInvalidScenarios(), kValidConfigurationList,
+ kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UpdateConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+ BluetoothLeAudioCodecsProviderTest, UpdateConfigurationsToMapTest,
+ ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+ kValidScenarioList,
+ UpdateConfigurationsToMapTest::CreateInvalidConfigurations(),
+ kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ UpdateCodecConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+ BluetoothLeAudioCodecsProviderTest, UpdateCodecConfigurationsToMapTest,
+ ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+ kValidScenarioList, kValidConfigurationList,
+ UpdateCodecConfigurationsToMapTest::CreateInvalidCodecConfigurations(),
+ kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ UpdateStrategyConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+ BluetoothLeAudioCodecsProviderTest, UpdateStrategyConfigurationsToMapTest,
+ ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+ kValidScenarioList, kValidConfigurationList,
+ kValidCodecConfigurationList,
+ UpdateStrategyConfigurationsToMapTest::
+ CreateInvalidStrategyConfigurations())));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ ComposeLeAudioCodecCapabilitiesTest);
+INSTANTIATE_TEST_SUITE_P(
+ BluetoothLeAudioCodecsProviderTest, ComposeLeAudioCodecCapabilitiesTest,
+ ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+ kValidScenarioList, kValidConfigurationList,
+ kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp b/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
index f511735..93c8376 100644
--- a/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
+++ b/boot/aidl/vts/functional/VtsHalBootAidlTargetTest.cpp
@@ -33,7 +33,7 @@
using std::unordered_set;
// The main test class for the Boot HIDL HAL.
-class BootHidlTest : public ::testing::TestWithParam<std::string> {
+class BootAidlTest : public ::testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
const auto instance_name = GetParam();
@@ -48,14 +48,14 @@
};
// validity check Boot::getNumberSlots().
-TEST_P(BootHidlTest, GetNumberSlots) {
+TEST_P(BootAidlTest, GetNumberSlots) {
int32_t slots{};
boot->getNumberSlots(&slots);
ASSERT_LE(2, slots);
}
// validity check Boot::getCurrentSlot().
-TEST_P(BootHidlTest, GetCurrentSlot) {
+TEST_P(BootAidlTest, GetCurrentSlot) {
int curSlot = -1;
boot->getCurrentSlot(&curSlot);
int slots = 0;
@@ -64,7 +64,7 @@
}
// validity check Boot::markBootSuccessful().
-TEST_P(BootHidlTest, MarkBootSuccessful) {
+TEST_P(BootAidlTest, MarkBootSuccessful) {
const auto result = boot->markBootSuccessful();
ASSERT_TRUE(result.isOk());
int curSlot = 0;
@@ -74,7 +74,7 @@
ASSERT_TRUE(ret);
}
-TEST_P(BootHidlTest, SetActiveBootSlot) {
+TEST_P(BootAidlTest, SetActiveBootSlot) {
int curSlot = -1;
boot->getCurrentSlot(&curSlot);
ASSERT_GE(curSlot, 0);
@@ -107,7 +107,7 @@
}
}
-TEST_P(BootHidlTest, SetSlotAsUnbootable) {
+TEST_P(BootAidlTest, SetSlotAsUnbootable) {
int curSlot = -1;
boot->getCurrentSlot(&curSlot);
ASSERT_GE(curSlot, 0);
@@ -139,7 +139,7 @@
}
// validity check Boot::isSlotBootable() on good and bad inputs.
-TEST_P(BootHidlTest, IsSlotBootable) {
+TEST_P(BootAidlTest, IsSlotBootable) {
for (int s = 0; s < 2; s++) {
bool bootable = false;
const auto res = boot->isSlotBootable(s, &bootable);
@@ -153,7 +153,7 @@
}
// validity check Boot::isSlotMarkedSuccessful() on good and bad inputs.
-TEST_P(BootHidlTest, IsSlotMarkedSuccessful) {
+TEST_P(BootAidlTest, IsSlotMarkedSuccessful) {
for (int32_t s = 0; s < 2; s++) {
bool isSuccess = false;
const auto res = boot->isSlotMarkedSuccessful(s, &isSuccess);
@@ -166,7 +166,7 @@
}
// validity check Boot::getSuffix() on good and bad inputs.
-TEST_P(BootHidlTest, GetSuffix) {
+TEST_P(BootAidlTest, GetSuffix) {
string suffixStr;
unordered_set<string> suffixes;
int numSlots = 0;
@@ -190,6 +190,6 @@
}
INSTANTIATE_TEST_SUITE_P(
- PerInstance, BootHidlTest,
+ PerInstance, BootAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IBootControl::descriptor)));
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BootHidlTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BootAidlTest);
diff --git a/camera/README.md b/camera/README.md
index 8ce3352..25badfd 100644
--- a/camera/README.md
+++ b/camera/README.md
@@ -10,3 +10,8 @@
More complete information about the Android camera HAL and subsystem can be found at
[source.android.com](http://source.android.com/devices/camera/index.html).
+
+### AIDL Camera HAL Interfaces
+
+The AIDL Camera HAL interfaces can be found in the respective <interface>/aidl
+directories.
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
index af414b4..ecbfc93 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -94,6 +94,10 @@
ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION = 65584,
ANDROID_CONTROL_SETTINGS_OVERRIDE = 65588,
ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES = 65589,
+ ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER = 65590,
+ ANDROID_CONTROL_AUTOFRAMING = 65591,
+ ANDROID_CONTROL_AUTOFRAMING_AVAILABLE = 65592,
+ ANDROID_CONTROL_AUTOFRAMING_STATE = 65593,
ANDROID_DEMOSAIC_MODE = 131072,
ANDROID_EDGE_MODE = 196608,
ANDROID_EDGE_STRENGTH = 196609,
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframing.aidl
similarity index 77%
copy from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
copy to camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframing.aidl
index 5ff45f8..eeb7bcd 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframing.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -12,6 +12,10 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
@@ -31,15 +35,10 @@
// 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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
- int versionNumber;
- @utf8InCpp String rpcAuthorName;
- int supportedEekCurve = 0;
- @nullable @utf8InCpp String uniqueId;
- const int CURVE_NONE = 0;
- const int CURVE_P256 = 1;
- const int CURVE_25519 = 2;
+package android.hardware.camera.metadata;
+@Backing(type="int") @VintfStability
+enum ControlAutoframing {
+ ANDROID_CONTROL_AUTOFRAMING_OFF = 0,
+ ANDROID_CONTROL_AUTOFRAMING_ON = 1,
+ ANDROID_CONTROL_AUTOFRAMING_AUTO = 2,
}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingAvailable.aidl
similarity index 77%
copy from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
copy to camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingAvailable.aidl
index 5ff45f8..b075c32 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingAvailable.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -12,6 +12,10 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
@@ -31,15 +35,9 @@
// 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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
- int versionNumber;
- @utf8InCpp String rpcAuthorName;
- int supportedEekCurve = 0;
- @nullable @utf8InCpp String uniqueId;
- const int CURVE_NONE = 0;
- const int CURVE_P256 = 1;
- const int CURVE_25519 = 2;
+package android.hardware.camera.metadata;
+@Backing(type="int") @VintfStability
+enum ControlAutoframingAvailable {
+ ANDROID_CONTROL_AUTOFRAMING_AVAILABLE_FALSE = 0,
+ ANDROID_CONTROL_AUTOFRAMING_AVAILABLE_TRUE = 1,
}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingState.aidl
similarity index 77%
copy from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
copy to camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingState.aidl
index 5ff45f8..60df0d4 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ControlAutoframingState.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -12,6 +12,10 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
+ *//*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
@@ -31,15 +35,10 @@
// 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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
- int versionNumber;
- @utf8InCpp String rpcAuthorName;
- int supportedEekCurve = 0;
- @nullable @utf8InCpp String uniqueId;
- const int CURVE_NONE = 0;
- const int CURVE_P256 = 1;
- const int CURVE_25519 = 2;
+package android.hardware.camera.metadata;
+@Backing(type="int") @VintfStability
+enum ControlAutoframingState {
+ ANDROID_CONTROL_AUTOFRAMING_STATE_INACTIVE = 0,
+ ANDROID_CONTROL_AUTOFRAMING_STATE_FRAMING = 1,
+ ANDROID_CONTROL_AUTOFRAMING_STATE_CONVERGED = 2,
}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index cc98ff0..2e9bde9 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -464,6 +464,32 @@
*/
ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES,
/**
+ * android.control.settingsOverridingFrameNumber [dynamic, int32, system]
+ *
+ * <p>The frame number of the newer request overriding this capture.</p>
+ */
+ ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER,
+ /**
+ * android.control.autoframing [dynamic, enum, public]
+ *
+ * <p>Automatic crop, pan and zoom to keep objects in the center of the frame.</p>
+ */
+ ANDROID_CONTROL_AUTOFRAMING,
+ /**
+ * android.control.autoframingAvailable [static, enum, public]
+ *
+ * <p>Whether the camera device supports ANDROID_CONTROL_AUTOFRAMING.</p>
+ *
+ * @see ANDROID_CONTROL_AUTOFRAMING
+ */
+ ANDROID_CONTROL_AUTOFRAMING_AVAILABLE,
+ /**
+ * android.control.autoframingState [dynamic, enum, public]
+ *
+ * <p>Current state of auto-framing.</p>
+ */
+ ANDROID_CONTROL_AUTOFRAMING_STATE,
+ /**
* android.demosaic.mode [controls, enum, system]
*
* <p>Controls the quality of the demosaicing
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframing.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframing.aidl
new file mode 100644
index 0000000..0fef373
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframing.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.control.autoframing enumeration values
+ * @see ANDROID_CONTROL_AUTOFRAMING
+ */
+@VintfStability
+@Backing(type="int")
+enum ControlAutoframing {
+ ANDROID_CONTROL_AUTOFRAMING_OFF,
+ ANDROID_CONTROL_AUTOFRAMING_ON,
+ ANDROID_CONTROL_AUTOFRAMING_AUTO,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingAvailable.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingAvailable.aidl
new file mode 100644
index 0000000..da0d348
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingAvailable.aidl
@@ -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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.control.autoframingAvailable enumeration values
+ * @see ANDROID_CONTROL_AUTOFRAMING_AVAILABLE
+ */
+@VintfStability
+@Backing(type="int")
+enum ControlAutoframingAvailable {
+ ANDROID_CONTROL_AUTOFRAMING_AVAILABLE_FALSE,
+ ANDROID_CONTROL_AUTOFRAMING_AVAILABLE_TRUE,
+}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingState.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingState.aidl
new file mode 100644
index 0000000..13183a5
--- /dev/null
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ControlAutoframingState.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata;
+
+/**
+ * android.control.autoframingState enumeration values
+ * @see ANDROID_CONTROL_AUTOFRAMING_STATE
+ */
+@VintfStability
+@Backing(type="int")
+enum ControlAutoframingState {
+ ANDROID_CONTROL_AUTOFRAMING_STATE_INACTIVE,
+ ANDROID_CONTROL_AUTOFRAMING_STATE_FRAMING,
+ ANDROID_CONTROL_AUTOFRAMING_STATE_CONVERGED,
+}
diff --git a/camera/provider/README.md b/camera/provider/README.md
index 0718fb1..7666a58 100644
--- a/camera/provider/README.md
+++ b/camera/provider/README.md
@@ -35,3 +35,9 @@
First HIDL version of the camara provider HAL callback interface, closely
matching the feature set and operation of the pre-HIDL camera HAL module
callbacks v2.4.
+
+### AIDL Camera HAL Default Implementation ###
+
+The default implementation can be found at
+$ANDROID_BUILD_TOP/hardware/google/camera/common/hal/aidl_service and
+$ANDROID_BUILD_TOP/hardware/google/camera/devices/EmulatedCamera
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 017f6ef..747ea33 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -2065,6 +2065,28 @@
}
}
+TEST_P(CameraAidlTest, processZoomSettingsOverrideRequests) {
+ const int32_t kFrameCount = 5;
+ const int32_t kTestCases = 2;
+ const bool kOverrideSequence[kTestCases][kFrameCount] = {
+ // ZOOM, ZOOM, ZOOM, ZOOM, ZOOM;
+ { true, true, true, true, true },
+ // OFF, OFF, ZOOM, ZOOM, OFF;
+ { false, false, true, true, false } };
+ const bool kExpectedOverrideResults[kTestCases][kFrameCount] = {
+ // All resuls should be overridden except the last one. The last result's
+ // zoom doesn't have speed-up.
+ { true, true, true, true, false },
+ // Because we require at least 2 frames speed-up, request #1, #2 and #3
+ // will be overridden.
+ { true, true, true, false, false } };
+
+ for (int i = 0; i < kTestCases; i++) {
+ processZoomSettingsOverrideRequests(kFrameCount, kOverrideSequence[i],
+ kExpectedOverrideResults[i]);
+ }
+}
+
// Generate and verify a burst containing alternating sensor sensitivity values
TEST_P(CameraAidlTest, processCaptureRequestBurstISO) {
std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index ca316e5..b9e30ab 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -363,10 +363,15 @@
retcode = find_camera_metadata_ro_entry(metadata,
ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
bool hasSettingsOverrideResultKey = false;
+ bool hasOverridingFrameNumberKey = false;
if ((0 == retcode) && (entry.count > 0)) {
hasSettingsOverrideResultKey =
std::find(entry.data.i32, entry.data.i32 + entry.count,
ANDROID_CONTROL_SETTINGS_OVERRIDE) != entry.data.i32 + entry.count;
+ hasOverridingFrameNumberKey =
+ std::find(entry.data.i32, entry.data.i32 + entry.count,
+ ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER)
+ != entry.data.i32 + entry.count;
} else {
ADD_FAILURE() << "Get camera availableResultKeys failed!";
}
@@ -385,6 +390,7 @@
ASSERT_EQ(supportSettingsOverride, hasSettingsOverrideRequestKey);
ASSERT_EQ(supportSettingsOverride, hasSettingsOverrideResultKey);
+ ASSERT_EQ(supportSettingsOverride, hasOverridingFrameNumberKey);
ASSERT_EQ(supportSettingsOverride, hasSettingsOverrideCharacteristicsKey);
}
@@ -1579,7 +1585,7 @@
// Check settings override
camera_metadata_ro_entry settingsOverrideEntry;
int foundSettingsOverride = find_camera_metadata_ro_entry(metadata,
- ANDROID_CONTROL_SETTINGS_OVERRIDE,&settingsOverrideEntry);
+ ANDROID_CONTROL_SETTINGS_OVERRIDE, &settingsOverrideEntry);
if (foundSettingsOverride == 0) {
ASSERT_EQ(settingsOverrideEntry.count, 1);
ASSERT_EQ(settingsOverrideEntry.data.u8[0], ANDROID_CONTROL_SETTINGS_OVERRIDE_OFF);
@@ -3019,6 +3025,30 @@
}
}
+bool CameraAidlTest::supportZoomSettingsOverride(const camera_metadata_t* staticMeta) {
+ camera_metadata_ro_entry availableOverridesEntry;
+ int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES,
+ &availableOverridesEntry);
+ if (rc == 0) {
+ for (size_t i = 0; i < availableOverridesEntry.count; i++) {
+ if (availableOverridesEntry.data.i32[i] == ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool CameraAidlTest::isPerFrameControl(const camera_metadata_t* staticMeta) {
+ camera_metadata_ro_entry syncLatencyEntry;
+ int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_SYNC_MAX_LATENCY,
+ &syncLatencyEntry);
+ if (rc == 0 && syncLatencyEntry.data.i32[0] == ANDROID_SYNC_MAX_LATENCY_PER_FRAME_CONTROL) {
+ return true;
+ }
+ return false;
+}
+
void CameraAidlTest::configurePreviewStream(
const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
const AvailableStream* previewThreshold, std::shared_ptr<ICameraDeviceSession>* session,
@@ -3385,3 +3415,158 @@
ASSERT_TRUE(ret.isOk());
}
}
+
+void CameraAidlTest::processZoomSettingsOverrideRequests(
+ int32_t frameCount, const bool *overrideSequence, const bool *expectedResults) {
+ std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+ AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
+ int64_t bufferId = 1;
+ int32_t frameNumber = 1;
+ CameraMetadata settings;
+ ndk::ScopedAStatus ret;
+ for (const auto& name : cameraDeviceNames) {
+ CameraMetadata meta;
+ std::shared_ptr<ICameraDevice> device;
+ openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+ &device /*out*/);
+ camera_metadata_t* staticMeta =
+ clone_camera_metadata(reinterpret_cast<camera_metadata_t*>(meta.metadata.data()));
+
+ ret = mSession->close();
+ mSession = nullptr;
+ ASSERT_TRUE(ret.isOk());
+
+ // Device does not support zoom settnigs override
+ if (!supportZoomSettingsOverride(staticMeta)) {
+ continue;
+ }
+
+ if (!isPerFrameControl(staticMeta)) {
+ continue;
+ }
+
+ bool supportsPartialResults = false;
+ bool useHalBufManager = false;
+ int32_t partialResultCount = 0;
+ Stream previewStream;
+ std::vector<HalStream> halStreams;
+ std::shared_ptr<DeviceCb> cb;
+ configurePreviewStream(name, mProvider, &previewThreshold, &mSession /*out*/,
+ &previewStream /*out*/, &halStreams /*out*/,
+ &supportsPartialResults /*out*/, &partialResultCount /*out*/,
+ &useHalBufManager /*out*/, &cb /*out*/);
+ ASSERT_NE(mSession, nullptr);
+
+ ::aidl::android::hardware::common::fmq::MQDescriptor<
+ int8_t, aidl::android::hardware::common::fmq::SynchronizedReadWrite>
+ descriptor;
+ auto resultQueueRet = mSession->getCaptureResultMetadataQueue(&descriptor);
+ ASSERT_TRUE(resultQueueRet.isOk());
+
+ std::shared_ptr<ResultMetadataQueue> resultQueue =
+ std::make_shared<ResultMetadataQueue>(descriptor);
+ if (!resultQueue->isValid() || resultQueue->availableToWrite() <= 0) {
+ ALOGE("%s: HAL returns empty result metadata fmq, not use it", __func__);
+ resultQueue = nullptr;
+ // Don't use the queue onwards.
+ }
+
+ ret = mSession->constructDefaultRequestSettings(RequestTemplate::PREVIEW, &settings);
+ ASSERT_TRUE(ret.isOk());
+
+ mInflightMap.clear();
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta;
+ std::vector<CaptureRequest> requests(frameCount);
+ std::vector<buffer_handle_t> buffers(frameCount);
+ std::vector<std::shared_ptr<InFlightRequest>> inflightReqs(frameCount);
+ std::vector<CameraMetadata> requestSettings(frameCount);
+
+ for (int32_t i = 0; i < frameCount; i++) {
+ std::unique_lock<std::mutex> l(mLock);
+ CaptureRequest& request = requests[i];
+ std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
+ outputBuffers.resize(1);
+ StreamBuffer& outputBuffer = outputBuffers[0];
+
+ if (useHalBufManager) {
+ outputBuffer = {halStreams[0].id, 0,
+ NativeHandle(), BufferStatus::OK,
+ NativeHandle(), NativeHandle()};
+ } else {
+ allocateGraphicBuffer(previewStream.width, previewStream.height,
+ android_convertGralloc1To0Usage(
+ static_cast<uint64_t>(halStreams[0].producerUsage),
+ static_cast<uint64_t>(halStreams[0].consumerUsage)),
+ halStreams[0].overrideFormat, &buffers[i]);
+ outputBuffer = {halStreams[0].id, bufferId + i, ::android::makeToAidl(buffers[i]),
+ BufferStatus::OK, NativeHandle(), NativeHandle()};
+ }
+
+ // Set appropriate settings override tag
+ requestMeta.append(reinterpret_cast<camera_metadata_t*>(settings.metadata.data()));
+ int32_t settingsOverride = overrideSequence[i] ?
+ ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM : ANDROID_CONTROL_SETTINGS_OVERRIDE_OFF;
+ ASSERT_EQ(::android::OK, requestMeta.update(ANDROID_CONTROL_SETTINGS_OVERRIDE,
+ &settingsOverride, 1));
+ camera_metadata_t* metaBuffer = requestMeta.release();
+ uint8_t* rawMetaBuffer = reinterpret_cast<uint8_t*>(metaBuffer);
+ requestSettings[i].metadata = std::vector(
+ rawMetaBuffer, rawMetaBuffer + get_camera_metadata_size(metaBuffer));
+ overrideRotateAndCrop(&(requestSettings[i]));
+ request.frameNumber = frameNumber + i;
+ request.fmqSettingsSize = 0;
+ request.settings = requestSettings[i];
+ request.inputBuffer = {
+ -1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
+
+ inflightReqs[i] = std::make_shared<InFlightRequest>(1, false, supportsPartialResults,
+ partialResultCount, resultQueue);
+ mInflightMap[frameNumber + i] = inflightReqs[i];
+ }
+
+ int32_t numRequestProcessed = 0;
+ std::vector<BufferCache> cachesToRemove;
+
+ ndk::ScopedAStatus returnStatus =
+ mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(numRequestProcessed, frameCount);
+
+ for (size_t i = 0; i < frameCount; i++) {
+ std::unique_lock<std::mutex> l(mLock);
+ while (!inflightReqs[i]->errorCodeValid && ((0 < inflightReqs[i]->numBuffersLeft) ||
+ (!inflightReqs[i]->haveResultMetadata))) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+ }
+
+ ASSERT_FALSE(inflightReqs[i]->errorCodeValid);
+ ASSERT_NE(inflightReqs[i]->resultOutputBuffers.size(), 0u);
+ ASSERT_EQ(previewStream.id, inflightReqs[i]->resultOutputBuffers[0].buffer.streamId);
+ ASSERT_FALSE(inflightReqs[i]->collectedResult.isEmpty());
+ ASSERT_TRUE(inflightReqs[i]->collectedResult.exists(ANDROID_CONTROL_SETTINGS_OVERRIDE));
+ camera_metadata_entry_t overrideResult =
+ inflightReqs[i]->collectedResult.find(ANDROID_CONTROL_SETTINGS_OVERRIDE);
+ ASSERT_EQ(overrideResult.data.i32[0] == ANDROID_CONTROL_SETTINGS_OVERRIDE_ZOOM,
+ expectedResults[i]);
+ ASSERT_TRUE(inflightReqs[i]->collectedResult.exists(
+ ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER));
+ camera_metadata_entry_t frameNumberEntry = inflightReqs[i]->collectedResult.find(
+ ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER);
+ ALOGV("%s: i %zu, expcetedResults[i] %d, overrideResult is %d, frameNumber %d",
+ __FUNCTION__, i, expectedResults[i], overrideResult.data.i32[0],
+ frameNumberEntry.data.i32[0]);
+ if (expectedResults[i]) {
+ ASSERT_GT(frameNumberEntry.data.i32[0], inflightReqs[i]->frameNumber);
+ } else {
+ ASSERT_EQ(frameNumberEntry.data.i32[0], frameNumber + i);
+ }
+ }
+
+ ret = mSession->close();
+ mSession = nullptr;
+ ASSERT_TRUE(ret.isOk());
+ }
+}
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index ff3617f..b6e398b 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -406,6 +406,12 @@
aidl::android::hardware::camera::metadata::
RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile);
+ void processZoomSettingsOverrideRequests(
+ int32_t frameCount, const bool *overrideSequence, const bool *expectedResults);
+
+ bool supportZoomSettingsOverride(const camera_metadata_t* staticMeta);
+ bool isPerFrameControl(const camera_metadata_t* staticMeta);
+
protected:
// In-flight queue for tracking completion of capture requests.
struct InFlightRequest {
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 4dc3f6c..37c2820 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -28,7 +28,6 @@
"compatibility_matrix.3.xml",
],
kernel_configs: [
- "kernel_config_p_4.9",
"kernel_config_p_4.14",
],
}
@@ -40,7 +39,6 @@
"compatibility_matrix.4.xml",
],
kernel_configs: [
- "kernel_config_q_4.9",
"kernel_config_q_4.14",
"kernel_config_q_4.19",
],
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index b3832c6..645753f 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -121,7 +121,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.biometrics.face</name>
- <version>2</version>
+ <version>3</version>
<interface>
<name>IFace</name>
<instance>default</instance>
@@ -129,7 +129,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.biometrics.fingerprint</name>
- <version>2</version>
+ <version>3</version>
<interface>
<name>IFingerprint</name>
<instance>default</instance>
@@ -173,7 +173,7 @@
<regex-instance>.*</regex-instance>
</interface>
</hal>
- <hal format="aidl" optional="true">
+ <hal format="aidl" optional="true" updatable-via-apex="true">
<name>android.hardware.camera.provider</name>
<version>1-2</version>
<interface>
@@ -268,7 +268,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.graphics.allocator</name>
- <version>1</version>
+ <version>1-2</version>
<interface>
<name>IAllocator</name>
<instance>default</instance>
@@ -282,7 +282,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="hidl" optional="true">
<name>android.hardware.graphics.mapper</name>
<!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
<version>2.1</version>
@@ -408,14 +408,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.neuralnetworks</name>
- <version>1.0-3</version>
- <interface>
- <name>IDevice</name>
- <regex-instance>.*</regex-instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.neuralnetworks</name>
<version>1-4</version>
@@ -456,7 +448,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.radio.config</name>
- <version>1</version>
+ <version>2</version>
<interface>
<name>IRadioConfig</name>
<instance>default</instance>
@@ -464,7 +456,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.radio.data</name>
- <version>1</version>
+ <version>2</version>
<interface>
<name>IRadioData</name>
<instance>slot1</instance>
@@ -474,7 +466,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.radio.messaging</name>
- <version>1</version>
+ <version>2</version>
<interface>
<name>IRadioMessaging</name>
<instance>slot1</instance>
@@ -484,7 +476,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.radio.modem</name>
- <version>1</version>
+ <version>2</version>
<interface>
<name>IRadioModem</name>
<instance>slot1</instance>
@@ -504,7 +496,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.radio.sim</name>
- <version>1</version>
+ <version>2</version>
<interface>
<name>IRadioSim</name>
<instance>slot1</instance>
@@ -514,7 +506,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.radio.voice</name>
- <version>1</version>
+ <version>2</version>
<interface>
<name>IRadioVoice</name>
<instance>slot1</instance>
@@ -740,6 +732,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.wifi.supplicant</name>
+ <version>2</version>
<interface>
<name>ISupplicant</name>
<instance>default</instance>
diff --git a/fastboot/aidl/default/Android.bp b/fastboot/aidl/default/Android.bp
index 5cd4542..0c96b33 100644
--- a/fastboot/aidl/default/Android.bp
+++ b/fastboot/aidl/default/Android.bp
@@ -22,16 +22,20 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-cc_library {
- name: "android.hardware.fastboot-impl-mock",
- recovery: true,
+cc_binary {
+ name: "android.hardware.fastboot-service.example_recovery",
+ init_rc: ["android.hardware.fastboot-service.example_recovery.rc"],
+ vintf_fragments: ["android.hardware.fastboot-service.example.xml"],
+ recovery_available: true,
srcs: [
"Fastboot.cpp",
+ "main.cpp",
],
relative_install_path: "hw",
shared_libs: [
"libbase",
"libbinder_ndk",
+ "liblog",
"libutils",
"libcutils",
"android.hardware.fastboot-V1-ndk",
diff --git a/fastboot/aidl/default/android.hardware.fastboot-service.example.xml b/fastboot/aidl/default/android.hardware.fastboot-service.example.xml
new file mode 100644
index 0000000..9490f98
--- /dev/null
+++ b/fastboot/aidl/default/android.hardware.fastboot-service.example.xml
@@ -0,0 +1,8 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.fastboot</name>
+ <version>1</version>
+ <fqname>IFastboot/default</fqname>
+ </hal>
+</manifest>
+
diff --git a/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc b/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc
new file mode 100644
index 0000000..5d4ee13
--- /dev/null
+++ b/fastboot/aidl/default/android.hardware.fastboot-service.example_recovery.rc
@@ -0,0 +1,6 @@
+service vendor.fastboot-default /system/bin/hw/android.hardware.fastboot-service.example_recovery
+ class hal
+ seclabel u:r:hal_fastboot_default:s0
+ user system
+ group system
+ interface aidl android.hardware.fastboot.IFastboot/default
diff --git a/fastboot/aidl/default/main.cpp b/fastboot/aidl/default/main.cpp
new file mode 100644
index 0000000..1b1b41d
--- /dev/null
+++ b/fastboot/aidl/default/main.cpp
@@ -0,0 +1,38 @@
+
+/*
+ * 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 <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include "Fastboot.h"
+
+using aidl::android::hardware::fastboot::Fastboot;
+using aidl::android::hardware::fastboot::IFastboot;
+
+int main(int, char* argv[]) {
+ android::base::InitLogging(argv, android::base::KernelLogger);
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<IFastboot> service = ndk::SharedRefBase::make<Fastboot>();
+
+ const std::string instance = std::string(IFastboot::descriptor) + "/default";
+ auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance << " " << status;
+ LOG(INFO) << "IFastboot AIDL service running...";
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/fastboot/aidl/fastbootshim/Android.bp b/fastboot/aidl/fastbootshim/Android.bp
new file mode 100644
index 0000000..c843c12
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/Android.bp
@@ -0,0 +1,61 @@
+// 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 {
+ // 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"],
+}
+
+cc_defaults {
+ name: "libfastbootshim_defaults",
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ static_libs: [
+ "android.hardware.fastboot-V1-ndk",
+ "android.hardware.fastboot@1.0",
+ "android.hardware.fastboot@1.1",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+}
+
+// Shim library that wraps a HIDL Fastboot object into an AIDL Fastboot object.
+cc_library_static {
+ name: "libfastbootshim",
+ defaults: ["libfastbootshim_defaults"],
+ recovery_available: true,
+ srcs: [
+ "fastbootshim.cpp",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+}
diff --git a/fastboot/aidl/fastbootshim/fastbootshim.cpp b/fastboot/aidl/fastbootshim/fastbootshim.cpp
new file mode 100644
index 0000000..4ab67f3
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/fastbootshim.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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 <fastbootshim.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Void;
+using ::android::hardware::fastboot::V1_0::FileSystemType;
+using ::android::hardware::fastboot::V1_0::Result;
+using ::android::hardware::fastboot::V1_0::Status;
+
+using ndk::ScopedAStatus;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+ScopedAStatus ResultToAStatus(Result result) {
+ switch (result.status) {
+ case Status::SUCCESS:
+ return ScopedAStatus::ok();
+ case Status::NOT_SUPPORTED:
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ case Status::INVALID_ARGUMENT:
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ case Status::FAILURE_UNKNOWN:
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ BnFastboot::FAILURE_UNKNOWN, ("Error " + std::string(result.message)).c_str());
+ }
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ BnFastboot::FAILURE_UNKNOWN,
+ ("Unrecognized status value " + toString(result.status)).c_str());
+}
+FastbootShim::FastbootShim(const sp<HidlFastboot>& service) : service_(service) {}
+
+ScopedAStatus FastbootShim::getPartitionType(const std::string& in_partitionName,
+ FileSystemType* _aidl_return) {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ if (in_partitionName.empty()) {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid partition name");
+ }
+ const hidl_string partition = in_partitionName;
+ auto ret = service_->getPartitionType(partition, [&](auto type, auto& result) {
+ out_result = result;
+ if (out_result.status != Status::SUCCESS) return;
+ *_aidl_return = static_cast<aidl::android::hardware::fastboot::FileSystemType>(type);
+ });
+ return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::doOemCommand(const std::string& in_oemCmd, std::string* _aidl_return) {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ *_aidl_return = "";
+ if (in_oemCmd.empty()) {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT, "Invalid command");
+ }
+ const hidl_string oemCmdArgs = in_oemCmd;
+ auto ret = service_->doOemCommand(oemCmdArgs, [&](auto& result) {
+ out_result = result;
+ if (out_result.status != Status::SUCCESS) return;
+ *_aidl_return = std::string(result.message.c_str());
+ });
+ return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getVariant(std::string* _aidl_return) {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ *_aidl_return = "";
+ auto ret = service_->getVariant([&](auto& variant, auto& result) {
+ out_result = result;
+ if (out_result.status != Status::SUCCESS) return;
+ *_aidl_return = std::string(variant.c_str());
+ });
+ return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getOffModeChargeState(bool* _aidl_return) {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ *_aidl_return = false;
+ auto ret = service_->getOffModeChargeState([&](auto state, auto& result) {
+ out_result = result;
+ if (out_result.status != Status::SUCCESS) return;
+ *_aidl_return = state;
+ });
+ return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ *_aidl_return = 0;
+ auto ret = service_->getBatteryVoltageFlashingThreshold([&](auto batteryVoltage, auto& result) {
+ out_result = result;
+ if (out_result.status != Status::SUCCESS) return;
+ *_aidl_return = batteryVoltage;
+ });
+ return ResultToAStatus(out_result);
+}
+
+ScopedAStatus FastbootShim::doOemSpecificErase() {
+ Result out_result = {Status::FAILURE_UNKNOWN, ""};
+ auto ret = service_->doOemSpecificErase([&](auto& result) { out_result = result; });
+ return ResultToAStatus(out_result);
+}
+
+} // namespace fastboot
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/fastboot/aidl/fastbootshim/include/fastbootshim.h b/fastboot/aidl/fastbootshim/include/fastbootshim.h
new file mode 100644
index 0000000..410a03e
--- /dev/null
+++ b/fastboot/aidl/fastbootshim/include/fastbootshim.h
@@ -0,0 +1,49 @@
+/*
+ * 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 <aidl/android/hardware/fastboot/BnFastboot.h>
+#include <android/hardware/fastboot/1.1/IFastboot.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace fastboot {
+// Shim that wraps HIDL IFastboot with AIDL BnFastboot
+class FastbootShim : public BnFastboot {
+ using HidlFastboot = ::android::hardware::fastboot::V1_1::IFastboot;
+
+ public:
+ explicit FastbootShim(const ::android::sp<HidlFastboot>& service);
+ ::ndk::ScopedAStatus doOemCommand(const std::string& in_oemCmd,
+ std::string* _aidl_return) override;
+ ::ndk::ScopedAStatus doOemSpecificErase() override;
+ ::ndk::ScopedAStatus getBatteryVoltageFlashingThreshold(int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus getOffModeChargeState(bool* _aidl_return) override;
+ ::ndk::ScopedAStatus getPartitionType(
+ const std::string& in_partitionName,
+ ::aidl::android::hardware::fastboot::FileSystemType* _aidl_return) override;
+ ::ndk::ScopedAStatus getVariant(std::string* _aidl_return) override;
+
+ private:
+ ::android::sp<HidlFastboot> service_;
+};
+
+} // namespace fastboot
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
index 31426f0..54e3b21 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssData.aidl
@@ -39,6 +39,7 @@
android.hardware.gnss.GnssClock clock;
android.hardware.gnss.ElapsedRealtime elapsedRealtime;
android.hardware.gnss.GnssData.GnssAgc[] gnssAgcs = {};
+ boolean isFullTracking;
@VintfStability
parcelable GnssAgc {
double agcLevelDb;
diff --git a/gnss/aidl/android/hardware/gnss/GnssData.aidl b/gnss/aidl/android/hardware/gnss/GnssData.aidl
index 075a039..492ba31 100644
--- a/gnss/aidl/android/hardware/gnss/GnssData.aidl
+++ b/gnss/aidl/android/hardware/gnss/GnssData.aidl
@@ -99,4 +99,15 @@
* weak to be acquired, the AGC value must still be reported.
*/
GnssAgc[] gnssAgcs = {};
+
+ /**
+ * True indicates that the GNSS chipset switches off duty cycling. In such mode, no clock
+ * discontinuities are expected and, when supported, carrier phase should be continuous in good
+ * signal conditions. All non-blocklisted, healthy constellations, satellites and frequency
+ * bands must be tracked and reported in this mode.
+ *
+ * False indicates that the GNSS chipset optimizes power via duty cycling, constellations and
+ * frequency limits, etc.
+ */
+ boolean isFullTracking;
}
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index 8a4d186..23d7999 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -68,7 +68,7 @@
IGnssCallback::GnssSystemInfo systemInfo = {
.yearOfHw = 2022,
- .name = "Google Mock GNSS Implementation AIDL v2",
+ .name = "Google, Cuttlefish, AIDL v3",
};
status = sGnssCallback->gnssSetSystemInfoCb(systemInfo);
if (!status.isOk()) {
@@ -76,12 +76,12 @@
}
GnssSignalType signalType1 = {
.constellation = GnssConstellationType::GPS,
- .carrierFrequencyHz = 1.59975e+09,
+ .carrierFrequencyHz = 1.57542e+09,
.codeType = GnssSignalType::CODE_TYPE_C,
};
GnssSignalType signalType2 = {
.constellation = GnssConstellationType::GLONASS,
- .carrierFrequencyHz = 1.59975e+09,
+ .carrierFrequencyHz = 1.5980625e+09,
.codeType = GnssSignalType::CODE_TYPE_C,
};
status = sGnssCallback->gnssSetSignalTypeCapabilitiesCb(
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index 606de07..90056ce 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -54,7 +54,7 @@
ALOGW("GnssMeasurement callback already set. Resetting the callback...");
stop();
}
- start(enableCorrVecOutputs);
+ start(enableCorrVecOutputs, enableFullTracking);
return ndk::ScopedAStatus::ok();
}
@@ -73,7 +73,7 @@
stop();
}
mIntervalMs = std::max(options.intervalMs, 1000);
- start(options.enableCorrVecOutputs);
+ start(options.enableCorrVecOutputs, options.enableFullTracking);
return ndk::ScopedAStatus::ok();
}
@@ -91,7 +91,8 @@
return ndk::ScopedAStatus::ok();
}
-void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) {
+void GnssMeasurementInterface::start(const bool enableCorrVecOutputs,
+ const bool enableFullTracking) {
ALOGD("start");
if (mIsActive) {
@@ -103,7 +104,7 @@
mIsActive = true;
mThreadBlocker.reset();
- mThread = std::thread([this, enableCorrVecOutputs]() {
+ mThread = std::thread([this, enableCorrVecOutputs, enableFullTracking]() {
int intervalMs;
do {
if (!mIsActive) {
@@ -122,7 +123,8 @@
this->reportMeasurement(*measurement);
}
} else {
- auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs);
+ auto measurement =
+ Utils::getMockMeasurement(enableCorrVecOutputs, enableFullTracking);
this->reportMeasurement(measurement);
}
intervalMs =
diff --git a/gnss/aidl/default/GnssMeasurementInterface.h b/gnss/aidl/default/GnssMeasurementInterface.h
index bb08027..d2737e5 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.h
+++ b/gnss/aidl/default/GnssMeasurementInterface.h
@@ -41,7 +41,7 @@
void setLocationEnabled(const bool enabled);
private:
- void start(const bool enableCorrVecOutputs);
+ void start(const bool enableCorrVecOutputs, const bool enableFullTracking);
void stop();
void reportMeasurement(const GnssData&);
void waitForStoppingThreads();
diff --git a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
index a553954..0d15b2a 100644
--- a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
+++ b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
@@ -24,9 +24,11 @@
android::binder::Status GnssMeasurementCallbackAidl::gnssMeasurementCb(const GnssData& gnssData) {
ALOGI("gnssMeasurementCb");
- ALOGV("elapsedRealtime: flags = 0x%X, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
+ ALOGV("elapsedRealtime: flags = 0x%X, timestampNs: %" PRId64
+ ", timeUncertaintyNs=%lf"
+ " isFullTracking=%s",
gnssData.elapsedRealtime.flags, gnssData.elapsedRealtime.timestampNs,
- gnssData.elapsedRealtime.timeUncertaintyNs);
+ gnssData.elapsedRealtime.timeUncertaintyNs, gnssData.isFullTracking ? "true" : "false");
gnss_data_cbq_.store(gnssData);
return android::binder::Status::ok();
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
index 91cd917..b4f2b77 100644
--- a/gnss/aidl/vts/gnss_hal_test.cpp
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -477,6 +477,26 @@
}
}
+void GnssHalTest::checkGnssDataFields(const sp<GnssMeasurementCallbackAidl>& callback,
+ const int numMeasurementEvents, const int timeoutSeconds,
+ const bool isFullTracking) {
+ for (int i = 0; i < numMeasurementEvents; i++) {
+ GnssData lastGnssData;
+ ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastGnssData, timeoutSeconds));
+ EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+ ASSERT_TRUE(lastGnssData.measurements.size() > 0);
+
+ // Validity check GnssData fields
+ checkGnssMeasurementClockFields(lastGnssData);
+ if (aidl_gnss_hal_->getInterfaceVersion() >= 3) {
+ EXPECT_EQ(lastGnssData.isFullTracking, isFullTracking);
+ }
+ for (const auto& measurement : lastGnssData.measurements) {
+ checkGnssMeasurementFields(measurement, lastGnssData);
+ }
+ }
+}
+
void GnssHalTest::assertMeanAndStdev(int intervalMs, std::vector<int>& deltasMs) {
double mean = computeMean(deltasMs);
double stdev = computeStdev(mean, deltasMs);
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
index c49c1b9..470294c 100644
--- a/gnss/aidl/vts/gnss_hal_test.h
+++ b/gnss/aidl/vts/gnss_hal_test.h
@@ -101,6 +101,9 @@
void collectMeasurementIntervals(const sp<GnssMeasurementCallbackAidl>& callback,
const int numMeasurementEvents, const int timeoutSeconds,
std::vector<int>& deltaMs);
+ void checkGnssDataFields(const sp<GnssMeasurementCallbackAidl>& callback,
+ const int numMeasurementEvents, const int timeoutSeconds,
+ const bool isFullTracking);
void assertMeanAndStdev(int intervalMillis, std::vector<int>& deltasMillis);
sp<IGnssAidl> aidl_gnss_hal_;
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 7c0a4df..31cef15 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -173,6 +173,7 @@
* GnssCapabilities:
* 1. Verifies that GNSS hardware supports measurement capabilities.
* 2. Verifies that GNSS hardware supports Scheduling capabilities.
+ * 3. Verifies that GNSS hardware supports non-empty signal type capabilities.
*/
TEST_P(GnssHalTest, GnssCapabilites) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
@@ -182,6 +183,10 @@
EXPECT_TRUE(aidl_gnss_cb_->last_capabilities_ & IGnssCallback::CAPABILITY_MEASUREMENTS);
}
EXPECT_TRUE(aidl_gnss_cb_->last_capabilities_ & IGnssCallback::CAPABILITY_SCHEDULING);
+ if (aidl_gnss_hal_->getInterfaceVersion() <= 2) {
+ return;
+ }
+ EXPECT_FALSE(aidl_gnss_cb_->last_signal_type_capabilities.empty());
}
/*
@@ -1466,7 +1471,7 @@
/*
* TestGnssMeasurementIntervals:
* 1. start measurement with interval
- * 2. verify that the received measurement intervals have expected mean and stdev
+ * 2. verify that the received measurement intervals have expected mean and stddev
*/
TEST_P(GnssHalTest, TestGnssMeasurementIntervals_LocationOnAfterMeasurement) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
@@ -1499,11 +1504,17 @@
}
}
+/*
+ * TestGnssMeasurementSetCallback
+ * 1. Start measurement with 20s interval. Expect the first measurement received in 10s.
+ * 2. Start measurement with 1s interval and wait for 5 measurements.
+ * 3. Verify the received measurement intervals have expected mean and stddev.
+ */
TEST_P(GnssHalTest, TestGnssMeasurementSetCallback) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 2) {
return;
}
-
+ const int kFirstGnssMeasurementTimeoutSeconds = 10;
sp<IGnssMeasurementInterface> iGnssMeasurement;
auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
ASSERT_TRUE(status.isOk());
@@ -1515,12 +1526,14 @@
// setCallback at 20s interval and wait for 1 measurement
startMeasurementWithInterval(20000, iGnssMeasurement, callback);
- collectMeasurementIntervals(callback, /* numEvents= */ 1, /* timeoutSeconds= */ 10, deltas);
+ collectMeasurementIntervals(callback, /* numEvents= */ 1, kFirstGnssMeasurementTimeoutSeconds,
+ deltas);
// setCallback at 1s interval and wait for 5 measurements
callback->gnss_data_cbq_.reset();
startMeasurementWithInterval(1000, iGnssMeasurement, callback);
- collectMeasurementIntervals(callback, /* numEvents= */ 5, /* timeoutSeconds= */ 10, deltas);
+ collectMeasurementIntervals(callback, /* numEvents= */ 5, kFirstGnssMeasurementTimeoutSeconds,
+ deltas);
// verify the measurements were received at 1Hz
assertMeanAndStdev(1000, deltas);
@@ -1528,3 +1541,43 @@
status = iGnssMeasurement->close();
ASSERT_TRUE(status.isOk());
}
+
+/*
+ * TestGnssMeasurementIsFullTracking
+ * 1. Start measurement with enableFullTracking=true. Verify the received measurements have
+ * isFullTracking=true.
+ * 2. Start measurement with enableFullTracking = false. Verify the received measurements have
+ * isFullTracking=false.
+ * 3. Do step 1 again.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIsFullTracking) {
+ // GnssData.isFullTracking is added in the interface version 3
+ if (aidl_gnss_hal_->getInterfaceVersion() <= 2) {
+ return;
+ }
+ const int kFirstGnssMeasurementTimeoutSeconds = 10;
+ const int kNumMeasurementEvents = 5;
+ std::vector<bool> isFullTrackingList({true, false, true});
+
+ sp<IGnssMeasurementInterface> iGnssMeasurement;
+ auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+ ALOGD("TestGnssMeasurementIsFullTracking");
+ auto callback = sp<GnssMeasurementCallbackAidl>::make();
+ IGnssMeasurementInterface::Options options;
+ options.intervalMs = 1000;
+
+ for (auto isFullTracking : isFullTrackingList) {
+ options.enableFullTracking = isFullTracking;
+
+ callback->gnss_data_cbq_.reset();
+ auto status = iGnssMeasurement->setCallbackWithOptions(callback, options);
+ checkGnssDataFields(callback, kNumMeasurementEvents, kFirstGnssMeasurementTimeoutSeconds,
+ isFullTracking);
+ }
+
+ status = iGnssMeasurement->close();
+ ASSERT_TRUE(status.isOk());
+}
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index 4de49f3..ad351f8 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -147,7 +147,7 @@
return gnssData;
}
-GnssData Utils::getMockMeasurement(const bool enableCorrVecOutputs) {
+GnssData Utils::getMockMeasurement(const bool enableCorrVecOutputs, const bool enableFullTracking) {
aidl::android::hardware::gnss::GnssSignalType signalType = {
.constellation = GnssConstellationType::GLONASS,
.carrierFrequencyHz = 1.59975e+09,
@@ -258,7 +258,8 @@
GnssData gnssData = {.measurements = {measurement},
.clock = clock,
.elapsedRealtime = timestamp,
- .gnssAgcs = std::vector({gnssAgc1, gnssAgc2})};
+ .gnssAgcs = std::vector({gnssAgc1, gnssAgc2}),
+ .isFullTracking = enableFullTracking};
return gnssData;
}
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index ad8f539..9be4a19 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -32,7 +32,7 @@
struct Utils {
static aidl::android::hardware::gnss::GnssData getMockMeasurement(
- const bool enableCorrVecOutputs);
+ const bool enableCorrVecOutputs, const bool enableFullTracking);
static V2_0::IGnssMeasurementCallback::GnssData getMockMeasurementV2_0();
static V2_1::IGnssMeasurementCallback::GnssData getMockMeasurementV2_1();
diff --git a/graphics/Android.bp b/graphics/Android.bp
index 1e9089f..4898dbe 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -19,14 +19,14 @@
cc_defaults {
name: "android.hardware.graphics.allocator-ndk_static",
static_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
+ "android.hardware.graphics.allocator-V2-ndk",
],
}
cc_defaults {
name: "android.hardware.graphics.allocator-ndk_shared",
shared_libs: [
- "android.hardware.graphics.allocator-V1-ndk",
+ "android.hardware.graphics.allocator-V2-ndk",
],
}
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
index 272ab48..098ef17 100644
--- a/graphics/allocator/aidl/Android.bp
+++ b/graphics/allocator/aidl/Android.bp
@@ -14,9 +14,11 @@
enabled: true,
support_system_process: true,
},
+ vndk_use_version: "2",
srcs: ["android/hardware/graphics/allocator/*.aidl"],
imports: [
"android.hardware.common-V2",
+ "android.hardware.graphics.common-V4",
],
stability: "vintf",
backend: {
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
similarity index 77%
copy from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
copy to graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
index 5ff45f8..980e246 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 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.
@@ -31,15 +31,14 @@
// 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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
- int versionNumber;
- @utf8InCpp String rpcAuthorName;
- int supportedEekCurve = 0;
- @nullable @utf8InCpp String uniqueId;
- const int CURVE_NONE = 0;
- const int CURVE_P256 = 1;
- const int CURVE_25519 = 2;
+package android.hardware.graphics.allocator;
+@VintfStability
+parcelable BufferDescriptorInfo {
+ byte[128] name;
+ int width;
+ int height;
+ int layerCount;
+ android.hardware.graphics.common.PixelFormat format = android.hardware.graphics.common.PixelFormat.UNSPECIFIED;
+ android.hardware.graphics.common.BufferUsage usage = android.hardware.graphics.common.BufferUsage.CPU_READ_NEVER;
+ long reservedSize;
}
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
index fe0b0a2..48bef16 100644
--- a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/IAllocator.aidl
@@ -34,5 +34,11 @@
package android.hardware.graphics.allocator;
@VintfStability
interface IAllocator {
+ /**
+ * @deprecated As of android.hardware.graphics.allocator-V2, this is deprecated & replaced with allocate2
+ */
android.hardware.graphics.allocator.AllocationResult allocate(in byte[] descriptor, in int count);
+ android.hardware.graphics.allocator.AllocationResult allocate2(in android.hardware.graphics.allocator.BufferDescriptorInfo descriptor, in int count);
+ boolean isSupported(in android.hardware.graphics.allocator.BufferDescriptorInfo descriptor);
+ String getIMapperLibrarySuffix();
}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
new file mode 100644
index 0000000..ffc50b8
--- /dev/null
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright 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.graphics.allocator;
+
+import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.PixelFormat;
+
+@VintfStability
+parcelable BufferDescriptorInfo {
+ /**
+ * The name of the buffer in ASCII. Useful for debugging/tracing.
+ */
+ byte[128] name;
+
+ /**
+ * The width specifies how many columns of pixels must be in the
+ * allocated buffer, but does not necessarily represent the offset in
+ * columns between the same column in adjacent rows. The rows may be
+ * padded.
+ */
+ int width;
+
+ /**
+ * The height specifies how many rows of pixels must be in the
+ * allocated buffer.
+ */
+ int height;
+
+ /**
+ * The number of image layers that must be in the allocated buffer.
+ */
+ int layerCount;
+
+ /**
+ * Buffer pixel format. See PixelFormat.aidl in graphics/common for
+ * valid values
+ */
+ PixelFormat format = PixelFormat.UNSPECIFIED;
+
+ /**
+ * Buffer usage mask; valid flags can be found in the definition of
+ * BufferUsage.aidl in graphics/common
+ */
+ BufferUsage usage = BufferUsage.CPU_READ_NEVER;
+
+ /**
+ * The size in bytes of the reserved region associated with the buffer.
+ * See getReservedRegion for more information.
+ */
+ long reservedSize;
+}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
index 92dfd4f..71cebd6 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/IAllocator.aidl
@@ -17,6 +17,7 @@
package android.hardware.graphics.allocator;
import android.hardware.graphics.allocator.AllocationResult;
+import android.hardware.graphics.allocator.BufferDescriptorInfo;
@VintfStability
interface IAllocator {
@@ -31,6 +32,43 @@
* @param count The number of buffers to allocate.
* @return An AllocationResult containing the result of the allocation
* @throws AllocationError on failure
+ * @deprecated As of android.hardware.graphics.allocator-V2, this is deprecated & replaced with
+ * allocate2
*/
AllocationResult allocate(in byte[] descriptor, in int count);
+
+ /**
+ * Allocates buffers with the properties specified by the descriptor.
+ *
+ * Allocations should be optimized for usage bits provided in the
+ * descriptor.
+ *
+ * @param descriptor Properties of the buffers to allocate. This must be
+ * obtained from IMapper::createDescriptor().
+ * @param count The number of buffers to allocate.
+ * @return An AllocationResult containing the result of the allocation
+ * @throws AllocationError on failure
+ */
+ AllocationResult allocate2(in BufferDescriptorInfo descriptor, in int count);
+
+ /**
+ * Test whether the given BufferDescriptorInfo is allocatable.
+ *
+ * If this function returns true, it means that a buffer with the given
+ * description can be allocated on this implementation, unless resource
+ * exhaustion occurs. If this function returns false, it means that the
+ * allocation of the given description will never succeed.
+ *
+ * @param description the description of the buffer
+ * @return supported whether the description is supported
+ */
+ boolean isSupported(in BufferDescriptorInfo descriptor);
+
+ /**
+ * Retrieve the library suffix to load for the IMapper SP-HAL. This library must implement the
+ * IMapper stable-C interface (android/hardware/graphics/mapper/IMapper.h).
+ *
+ * The library that will attempt to be loaded is "/vendor/lib[64]/hw/mapper.<imapper_suffix>.so"
+ */
+ String getIMapperLibrarySuffix();
}
diff --git a/graphics/allocator/aidl/vts/Android.bp b/graphics/allocator/aidl/vts/Android.bp
index a38af14..630ab2a 100644
--- a/graphics/allocator/aidl/vts/Android.bp
+++ b/graphics/allocator/aidl/vts/Android.bp
@@ -55,6 +55,7 @@
],
header_libs: [
"libhwui_internal_headers",
+ "libimapper_stablec",
],
cflags: [
"-Wall",
diff --git a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
index 59af5cf..09f1c15 100644
--- a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
+++ b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
@@ -25,7 +25,10 @@
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <aidlcommonsupport/NativeHandle.h>
#include <android/binder_manager.h>
+#include <android/dlext.h>
#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+#include <dlfcn.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
@@ -33,6 +36,7 @@
#include <renderthread/EglManager.h>
#include <utils/GLUtils.h>
#include <vndk/hardware_buffer.h>
+#include <vndksupport/linker.h>
#include <initializer_list>
#include <optional>
#include <string>
@@ -42,60 +46,70 @@
using namespace aidl::android::hardware::graphics::common;
using namespace android;
using namespace android::hardware;
-using namespace android::hardware::graphics::mapper::V4_0;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
+using Error = android::hardware::graphics::mapper::V4_0::Error;
+using android::hardware::graphics::mapper::V4_0::BufferDescriptor;
using android::uirenderer::AutoEglImage;
using android::uirenderer::AutoGLFramebuffer;
using android::uirenderer::AutoSkiaGlTexture;
using android::uirenderer::renderthread::EglManager;
-static constexpr uint64_t pack(const std::initializer_list<BufferUsage>& usages) {
- uint64_t ret = 0;
- for (const auto u : usages) {
- ret |= static_cast<uint64_t>(u);
- }
- return ret;
+typedef AIMapper_Error (*AIMapper_loadIMapperFn)(AIMapper* _Nullable* _Nonnull outImplementation);
+
+inline BufferUsage operator|(BufferUsage lhs, BufferUsage rhs) {
+ using T = std::underlying_type_t<BufferUsage>;
+ return static_cast<BufferUsage>(static_cast<T>(lhs) | static_cast<T>(rhs));
}
-static constexpr hardware::graphics::common::V1_2::PixelFormat cast(PixelFormat format) {
- return static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
+inline BufferUsage& operator|=(BufferUsage& lhs, BufferUsage rhs) {
+ lhs = lhs | rhs;
+ return lhs;
}
+static IMapper4::BufferDescriptorInfo convert(const BufferDescriptorInfo& info) {
+ return IMapper4::BufferDescriptorInfo{
+ .name{reinterpret_cast<const char*>(info.name.data())},
+ .width = static_cast<uint32_t>(info.width),
+ .height = static_cast<uint32_t>(info.height),
+ .layerCount = static_cast<uint32_t>(info.layerCount),
+ .format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(info.format),
+ .usage = static_cast<uint64_t>(info.usage),
+ .reservedSize = 0,
+ };
+}
+
+class GraphicsTestsBase;
+
class BufferHandle {
- sp<IMapper> mMapper;
+ GraphicsTestsBase& mTestBase;
native_handle_t* mRawHandle;
bool mImported = false;
uint32_t mStride;
- const IMapper::BufferDescriptorInfo mInfo;
+ const BufferDescriptorInfo mInfo;
BufferHandle(const BufferHandle&) = delete;
void operator=(const BufferHandle&) = delete;
public:
- BufferHandle(const sp<IMapper> mapper, native_handle_t* handle, bool imported, uint32_t stride,
- const IMapper::BufferDescriptorInfo& info)
- : mMapper(mapper), mRawHandle(handle), mImported(imported), mStride(stride), mInfo(info) {}
+ BufferHandle(GraphicsTestsBase& testBase, native_handle_t* handle, bool imported,
+ uint32_t stride, const BufferDescriptorInfo& info)
+ : mTestBase(testBase),
+ mRawHandle(handle),
+ mImported(imported),
+ mStride(stride),
+ mInfo(info) {}
- ~BufferHandle() {
- if (mRawHandle == nullptr) return;
-
- if (mImported) {
- Error error = mMapper->freeBuffer(mRawHandle);
- EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
- } else {
- native_handle_close(mRawHandle);
- native_handle_delete(mRawHandle);
- }
- }
+ ~BufferHandle();
uint32_t stride() const { return mStride; }
AHardwareBuffer_Desc describe() const {
return {
- .width = mInfo.width,
- .height = mInfo.height,
- .layers = mInfo.layerCount,
+ .width = static_cast<uint32_t>(mInfo.width),
+ .height = static_cast<uint32_t>(mInfo.height),
+ .layers = static_cast<uint32_t>(mInfo.layerCount),
.format = static_cast<uint32_t>(mInfo.format),
- .usage = mInfo.usage,
+ .usage = static_cast<uint64_t>(mInfo.usage),
.stride = stride(),
.rfu0 = 0,
.rfu1 = 0,
@@ -114,25 +128,43 @@
class GraphicsTestsBase {
private:
+ friend class BufferHandle;
+ int32_t mIAllocatorVersion = 1;
std::shared_ptr<IAllocator> mAllocator;
- sp<IMapper> mMapper;
+ sp<IMapper4> mMapper4;
+ AIMapper* mAIMapper = nullptr;
protected:
- void Initialize(std::string allocatorService, std::string mapperService) {
+ void Initialize(std::string allocatorService) {
mAllocator = IAllocator::fromBinder(
ndk::SpAIBinder(AServiceManager_checkService(allocatorService.c_str())));
- mMapper = IMapper::getService(mapperService);
+ ASSERT_TRUE(mAllocator->getInterfaceVersion(&mIAllocatorVersion).isOk());
+ if (mIAllocatorVersion >= 2) {
+ std::string mapperSuffix;
+ auto status = mAllocator->getIMapperLibrarySuffix(&mapperSuffix);
+ ASSERT_TRUE(status.isOk());
+ std::string lib_name = "mapper." + mapperSuffix + ".so";
+ void* so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, so) << "Failed to load " << lib_name;
+ auto loadIMapper = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
+ ASSERT_NE(nullptr, loadIMapper) << "AIMapper_locaIMapper missing from " << lib_name;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, loadIMapper(&mAIMapper));
+ ASSERT_NE(mAIMapper, nullptr);
+ } else {
+ // Don't have IMapper 5, fall back to IMapper 4
+ mMapper4 = IMapper4::getService();
+ ASSERT_NE(nullptr, mMapper4.get()) << "failed to get mapper service";
+ ASSERT_FALSE(mMapper4->isRemote()) << "mapper is not in passthrough mode";
+ }
ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
- ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
- ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
}
- public:
- BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+ private:
+ BufferDescriptor createDescriptor(const BufferDescriptorInfo& descriptorInfo) {
BufferDescriptor descriptor;
- mMapper->createDescriptor(
- descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
+ mMapper4->createDescriptor(
+ convert(descriptorInfo), [&](const auto& tmpError, const auto& tmpDescriptor) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
descriptor = tmpDescriptor;
});
@@ -140,14 +172,22 @@
return descriptor;
}
- std::unique_ptr<BufferHandle> allocate(const IMapper::BufferDescriptorInfo& descriptorInfo) {
- auto descriptor = createDescriptor(descriptorInfo);
- if (::testing::Test::HasFatalFailure()) {
- return nullptr;
- }
-
+ public:
+ std::unique_ptr<BufferHandle> allocate(const BufferDescriptorInfo& descriptorInfo) {
AllocationResult result;
- auto status = mAllocator->allocate(descriptor, 1, &result);
+ ::ndk::ScopedAStatus status;
+ if (mIAllocatorVersion >= 2) {
+ status = mAllocator->allocate2(descriptorInfo, 1, &result);
+ } else {
+ auto descriptor = createDescriptor(descriptorInfo);
+ if (::testing::Test::HasFatalFailure()) {
+ return nullptr;
+ }
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ status = mAllocator->allocate(descriptor, 1, &result);
+#pragma clang diagnostic pop // deprecation
+ }
if (!status.isOk()) {
status_t error = status.getExceptionCode();
if (error == EX_SERVICE_SPECIFIC) {
@@ -158,28 +198,48 @@
}
return nullptr;
} else {
- return std::make_unique<BufferHandle>(mMapper, dupFromAidl(result.buffers[0]), false,
+ return std::make_unique<BufferHandle>(*this, dupFromAidl(result.buffers[0]), false,
result.stride, descriptorInfo);
}
}
- bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+ bool isSupported(const BufferDescriptorInfo& descriptorInfo) {
bool ret = false;
- EXPECT_TRUE(mMapper->isSupported(descriptorInfo,
- [&](auto error, bool supported) {
- ASSERT_EQ(Error::NONE, error);
- ret = supported;
- })
- .isOk());
+ if (mIAllocatorVersion >= 2) {
+ EXPECT_TRUE(mAllocator->isSupported(descriptorInfo, &ret).isOk());
+ } else {
+ EXPECT_TRUE(mMapper4->isSupported(convert(descriptorInfo),
+ [&](auto error, bool supported) {
+ ASSERT_EQ(Error::NONE, error);
+ ret = supported;
+ })
+ .isOk());
+ }
return ret;
}
};
-class GraphicsAllocatorAidlTests
- : public GraphicsTestsBase,
- public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+BufferHandle::~BufferHandle() {
+ if (mRawHandle == nullptr) return;
+
+ if (mImported) {
+ if (mTestBase.mAIMapper) {
+ AIMapper_Error error = mTestBase.mAIMapper->v5.freeBuffer(mRawHandle);
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, error);
+ } else {
+ Error error = mTestBase.mMapper4->freeBuffer(mRawHandle);
+ EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
+ }
+ } else {
+ native_handle_close(mRawHandle);
+ native_handle_delete(mRawHandle);
+ }
+}
+
+class GraphicsAllocatorAidlTests : public GraphicsTestsBase,
+ public ::testing::TestWithParam<std::string> {
public:
- void SetUp() override { Initialize(std::get<0>(GetParam()), std::get<1>(GetParam())); }
+ void SetUp() override { Initialize(GetParam()); }
void TearDown() override {}
};
@@ -191,22 +251,22 @@
class GraphicsFrontBufferTests
: public GraphicsTestsBase,
- public ::testing::TestWithParam<std::tuple<std::string, std::string, FlushMethod>> {
+ public ::testing::TestWithParam<std::tuple<std::string, FlushMethod>> {
private:
EglManager eglManager;
std::function<void(EglManager&)> flush;
public:
void SetUp() override {
- Initialize(std::get<0>(GetParam()), std::get<1>(GetParam()));
- flush = std::get<2>(GetParam()).func;
+ Initialize(std::get<0>(GetParam()));
+ flush = std::get<1>(GetParam()).func;
eglManager.initialize();
}
void TearDown() override { eglManager.destroy(); }
void fillWithGpu(AHardwareBuffer* buffer, float red, float green, float blue, float alpha) {
- const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
+ EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
AutoEglImage eglImage(eglManager.eglDisplay(), clientBuffer);
AutoSkiaGlTexture glTexture;
AutoGLFramebuffer glFbo;
@@ -235,26 +295,14 @@
}
};
-TEST_P(GraphicsAllocatorAidlTests, CreateDescriptorBasic) {
- ASSERT_NO_FATAL_FAILURE(createDescriptor({
- .name = "CPU_8888",
- .width = 64,
- .height = 64,
- .layerCount = 1,
- .format = cast(PixelFormat::RGBA_8888),
- .usage = pack({BufferUsage::CPU_WRITE_OFTEN, BufferUsage::CPU_READ_OFTEN}),
- .reservedSize = 0,
- }));
-}
-
TEST_P(GraphicsAllocatorAidlTests, CanAllocate) {
auto buffer = allocate({
- .name = "CPU_8888",
+ .name = {"CPU_8888"},
.width = 64,
.height = 64,
.layerCount = 1,
- .format = cast(PixelFormat::RGBA_8888),
- .usage = pack({BufferUsage::CPU_WRITE_OFTEN, BufferUsage::CPU_READ_OFTEN}),
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
.reservedSize = 0,
});
ASSERT_NE(nullptr, buffer.get());
@@ -262,14 +310,14 @@
}
TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
- IMapper::BufferDescriptorInfo info{
- .name = "CPU_8888",
+ BufferDescriptorInfo info{
+ .name = {"CPU_8888"},
.width = 64,
.height = 64,
.layerCount = 1,
- .format = cast(PixelFormat::RGBA_8888),
- .usage = pack({BufferUsage::GPU_RENDER_TARGET, BufferUsage::CPU_READ_OFTEN,
- BufferUsage::FRONT_BUFFER}),
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::CPU_READ_OFTEN |
+ BufferUsage::FRONT_BUFFER,
.reservedSize = 0,
};
const bool supported = isSupported(info);
@@ -304,14 +352,14 @@
}
TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToGpu) {
- IMapper::BufferDescriptorInfo info{
- .name = "CPU_8888",
+ BufferDescriptorInfo info{
+ .name = {"CPU_8888"},
.width = 64,
.height = 64,
.layerCount = 1,
- .format = cast(PixelFormat::RGBA_8888),
- .usage = pack({BufferUsage::GPU_RENDER_TARGET, BufferUsage::GPU_TEXTURE,
- BufferUsage::FRONT_BUFFER}),
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::GPU_TEXTURE |
+ BufferUsage::FRONT_BUFFER,
.reservedSize = 0,
};
const bool supported = isSupported(info);
@@ -344,11 +392,9 @@
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsAllocatorAidlTests);
-INSTANTIATE_TEST_CASE_P(
- PerInstance, GraphicsAllocatorAidlTests,
- testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
- testing::ValuesIn(getAllHalInstanceNames(IMapper::descriptor))),
- PrintInstanceTupleNameToString<>);
+INSTANTIATE_TEST_CASE_P(PerInstance, GraphicsAllocatorAidlTests,
+ testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
+ PrintInstanceNameToString);
const auto FlushMethodsValues = testing::Values(
FlushMethod{"glFinish", [](EglManager&) { glFinish(); }},
@@ -362,7 +408,7 @@
}},
FlushMethod{"eglClientWaitSync", [](EglManager& eglManager) {
EGLDisplay display = eglManager.eglDisplay();
- EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
+ EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
EGL_FOREVER_KHR);
eglDestroySyncKHR(display, fence);
@@ -371,9 +417,8 @@
INSTANTIATE_TEST_CASE_P(
PerInstance, GraphicsFrontBufferTests,
testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
- testing::ValuesIn(getAllHalInstanceNames(IMapper::descriptor)),
FlushMethodsValues),
[](auto info) -> std::string {
- std::string name = std::to_string(info.index) + "/" + std::get<2>(info.param).name;
+ std::string name = std::to_string(info.index) + "/" + std::get<1>(info.param).name;
return Sanitize(name);
- });
+ });
\ No newline at end of file
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index cb96663..84bc1af 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -40,6 +40,7 @@
min_sdk_version: "29",
},
},
+ frozen: false,
versions_with_info: [
{
version: "1",
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
index 27dce76..76ba24b 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h
@@ -19,8 +19,8 @@
#include <algorithm>
#include <limits>
#include <memory>
+#include <optional>
#include <unordered_map>
-#include <unordered_set>
#include <vector>
#include <inttypes.h>
@@ -41,8 +41,15 @@
class ComposerClientReader {
public:
+ explicit ComposerClientReader(std::optional<int64_t> display = {}) : mDisplay(display) {}
+
~ComposerClientReader() { resetData(); }
+ ComposerClientReader(ComposerClientReader&&) = default;
+
+ ComposerClientReader(const ComposerClientReader&) = delete;
+ ComposerClientReader& operator=(const ComposerClientReader&) = delete;
+
// Parse and execute commands from the command queue. The commands are
// actually return values from the server and will be saved in ReturnData.
void parse(std::vector<CommandResultPayload>&& results) {
@@ -85,6 +92,7 @@
void hasChanges(int64_t display, uint32_t* outNumChangedCompositionTypes,
uint32_t* outNumLayerRequestMasks) const {
+ LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
auto found = mReturnData.find(display);
if (found == mReturnData.end()) {
*outNumChangedCompositionTypes = 0;
@@ -100,6 +108,7 @@
// Get and clear saved changed composition types.
std::vector<ChangedCompositionLayer> takeChangedCompositionTypes(int64_t display) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
auto found = mReturnData.find(display);
if (found == mReturnData.end()) {
return {};
@@ -111,6 +120,7 @@
// Get and clear saved display requests.
DisplayRequest takeDisplayRequests(int64_t display) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
auto found = mReturnData.find(display);
if (found == mReturnData.end()) {
return {};
@@ -122,6 +132,7 @@
// Get and clear saved release fences.
std::vector<ReleaseFences::Layer> takeReleaseFences(int64_t display) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
auto found = mReturnData.find(display);
if (found == mReturnData.end()) {
return {};
@@ -133,6 +144,7 @@
// Get and clear saved present fence.
ndk::ScopedFileDescriptor takePresentFence(int64_t display) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
auto found = mReturnData.find(display);
if (found == mReturnData.end()) {
return {};
@@ -144,6 +156,7 @@
// Get what stage succeeded during PresentOrValidate: Present or Validate
std::optional<PresentOrValidate::Result> takePresentOrValidateStage(int64_t display) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
auto found = mReturnData.find(display);
if (found == mReturnData.end()) {
return std::nullopt;
@@ -154,6 +167,7 @@
// Get the client target properties requested by hardware composer.
ClientTargetPropertyWithBrightness takeClientTargetProperty(int64_t display) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay);
auto found = mReturnData.find(display);
// If not found, return the default values.
@@ -177,32 +191,38 @@
void parseSetError(CommandError&& error) { mErrors.emplace_back(error); }
void parseSetChangedCompositionTypes(ChangedCompositionTypes&& changedCompositionTypes) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && changedCompositionTypes.display != *mDisplay);
auto& data = mReturnData[changedCompositionTypes.display];
data.changedLayers = std::move(changedCompositionTypes.layers);
}
void parseSetDisplayRequests(DisplayRequest&& displayRequest) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && displayRequest.display != *mDisplay);
auto& data = mReturnData[displayRequest.display];
data.displayRequests = std::move(displayRequest);
}
void parseSetPresentFence(PresentFence&& presentFence) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && presentFence.display != *mDisplay);
auto& data = mReturnData[presentFence.display];
data.presentFence = std::move(presentFence.fence);
}
void parseSetReleaseFences(ReleaseFences&& releaseFences) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && releaseFences.display != *mDisplay);
auto& data = mReturnData[releaseFences.display];
data.releasedLayers = std::move(releaseFences.layers);
}
void parseSetPresentOrValidateDisplayResult(const PresentOrValidate&& presentOrValidate) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && presentOrValidate.display != *mDisplay);
auto& data = mReturnData[presentOrValidate.display];
data.presentOrValidateState = std::move(presentOrValidate.result);
}
void parseSetClientTargetProperty(
const ClientTargetPropertyWithBrightness&& clientTargetProperty) {
+ LOG_ALWAYS_FATAL_IF(mDisplay && clientTargetProperty.display != *mDisplay);
auto& data = mReturnData[clientTargetProperty.display];
data.clientTargetProperty = std::move(clientTargetProperty);
}
@@ -222,6 +242,7 @@
std::vector<CommandError> mErrors;
std::unordered_map<int64_t, ReturnData> mReturnData;
+ const std::optional<int64_t> mDisplay;
};
} // namespace aidl::android::hardware::graphics::composer3
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
index 775ae9f..0c8742f 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -19,8 +19,6 @@
#include <algorithm>
#include <limits>
#include <memory>
-#include <unordered_map>
-#include <unordered_set>
#include <vector>
#include <inttypes.h>
@@ -63,10 +61,15 @@
public:
static constexpr std::optional<ClockMonotonicTimestamp> kNoTimestamp = std::nullopt;
- ComposerClientWriter() { reset(); }
+ explicit ComposerClientWriter(int64_t display) : mDisplay(display) { reset(); }
~ComposerClientWriter() { reset(); }
+ ComposerClientWriter(ComposerClientWriter&&) = default;
+
+ ComposerClientWriter(const ComposerClientWriter&) = delete;
+ ComposerClientWriter& operator=(const ComposerClientWriter&) = delete;
+
void reset() {
mDisplayCommand.reset();
mLayerCommand.reset();
@@ -229,6 +232,7 @@
std::optional<DisplayCommand> mDisplayCommand;
std::optional<LayerCommand> mLayerCommand;
std::vector<DisplayCommand> mCommands;
+ const int64_t mDisplay;
Buffer getBuffer(uint32_t slot, const native_handle_t* bufferHandle, int fence) {
Buffer bufferCommand;
@@ -254,6 +258,7 @@
DisplayCommand& getDisplayCommand(int64_t display) {
if (!mDisplayCommand.has_value() || mDisplayCommand->display != display) {
+ LOG_ALWAYS_FATAL_IF(display != mDisplay);
flushLayerCommand();
flushDisplayCommand();
mDisplayCommand.emplace();
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index 6358b85..1883336 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -35,6 +35,7 @@
#include <string>
#include <thread>
#include <unordered_map>
+#include <unordered_set>
#include "GraphicsComposerCallback.h"
using aidl::android::hardware::graphics::common::Dataspace;
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 46dde09..6fa3392 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -53,6 +53,7 @@
const auto& [status, displays] = mComposerClient->getDisplays();
ASSERT_TRUE(status.isOk());
mDisplays = displays;
+ mWriter.reset(new ComposerClientWriter(getPrimaryDisplayId()));
setTestColorModes();
@@ -200,15 +201,15 @@
void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
for (const auto& layer : layers) {
- layer->write(mWriter);
+ layer->write(*mWriter);
}
execute();
}
void execute() {
- const auto& commands = mWriter.getPendingCommands();
+ const auto& commands = mWriter->getPendingCommands();
if (commands.empty()) {
- mWriter.reset();
+ mWriter->reset();
return;
}
@@ -216,7 +217,7 @@
ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
mReader.parse(std::move(results));
- mWriter.reset();
+ mWriter->reset();
}
bool getHasReadbackBuffer() {
@@ -236,7 +237,7 @@
std::vector<VtsDisplay> mDisplays;
// use the slot count usually set by SF
std::vector<ColorMode> mTestColorModes;
- ComposerClientWriter mWriter;
+ std::unique_ptr<ComposerClientWriter> mWriter;
ComposerClientReader mReader;
std::unique_ptr<TestRenderEngine> mTestRenderEngine;
common::PixelFormat mPixelFormat;
@@ -297,7 +298,7 @@
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
// if hwc cannot handle and asks for composition change,
// just succeed the test
@@ -306,7 +307,7 @@
return;
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -349,14 +350,14 @@
getDisplayHeight(), common::PixelFormat::RGBA_8888);
layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
layer->setZOrder(10);
- layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
@@ -365,7 +366,7 @@
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -395,7 +396,7 @@
layer->setColor(BLUE);
layer->setDisplayFrame(coloredSquare);
layer->setZOrder(10);
- layer->write(mWriter);
+ layer->write(*mWriter);
// This following buffer call should have no effect
const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
@@ -403,8 +404,8 @@
const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage);
ASSERT_TRUE(graphicBufferStatus);
const auto& buffer = graphicBuffer->handle;
- mWriter.setLayerBuffer(getPrimaryDisplayId(), layer->getLayer(), /*slot*/ 0, buffer,
- /*acquireFence*/ -1);
+ mWriter->setLayerBuffer(getPrimaryDisplayId(), layer->getLayer(), /*slot*/ 0, buffer,
+ /*acquireFence*/ -1);
// expected color for each pixel
std::vector<Color> expectedColors(
@@ -415,7 +416,7 @@
getDisplayHeight(), mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
@@ -423,7 +424,7 @@
return;
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -533,7 +534,7 @@
getDisplayHeight(), PixelFormat::RGBA_FP16);
layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
layer->setZOrder(10);
- layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
@@ -542,7 +543,7 @@
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
auto changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
@@ -572,17 +573,17 @@
int32_t clientFence;
const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
ASSERT_EQ(::android::OK, unlockStatus);
- mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
- clientDataspace, std::vector<common::Rect>(1, damage));
- layer->setToClientComposition(mWriter);
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
+ clientDataspace, std::vector<common::Rect>(1, damage));
+ layer->setToClientComposition(*mWriter);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
ASSERT_TRUE(changedCompositionTypes.empty());
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -631,9 +632,9 @@
deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->getWidth()),
static_cast<int32_t>(deviceLayer->getHeight())});
deviceLayer->setZOrder(10);
- deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
- deviceLayer->write(mWriter);
+ deviceLayer->write(*mWriter);
PixelFormat clientFormat = PixelFormat::RGBA_8888;
auto clientUsage = static_cast<uint32_t>(
@@ -651,8 +652,8 @@
getDisplayHeight()};
clientLayer->setDisplayFrame(clientFrame);
clientLayer->setZOrder(0);
- clientLayer->write(mWriter);
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ clientLayer->write(*mWriter);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
auto changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
@@ -678,16 +679,16 @@
int32_t clientFence;
const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
ASSERT_EQ(::android::OK, unlockStatus);
- mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
- clientDataspace, std::vector<common::Rect>(1, clientFrame));
- clientLayer->setToClientComposition(mWriter);
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence,
+ clientDataspace, std::vector<common::Rect>(1, clientFrame));
+ clientLayer->setToClientComposition(*mWriter);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId());
ASSERT_TRUE(changedCompositionTypes.empty());
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
@@ -718,7 +719,7 @@
getDisplayHeight(), PixelFormat::RGBA_8888);
layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
layer->setZOrder(10);
- layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
@@ -729,14 +730,14 @@
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED();
return;
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -757,11 +758,11 @@
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -798,7 +799,7 @@
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED();
@@ -806,7 +807,7 @@
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -846,7 +847,7 @@
getDisplayHeight(), PixelFormat::RGBA_8888);
layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
layer->setZOrder(10);
- layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
layer->setSourceCrop({0, static_cast<float>(getDisplayHeight() / 2),
static_cast<float>(getDisplayWidth()),
static_cast<float>(getDisplayHeight())});
@@ -862,14 +863,14 @@
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED();
return;
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
@@ -920,13 +921,13 @@
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED();
return;
}
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -942,11 +943,11 @@
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty());
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -980,7 +981,7 @@
// Preconditions to successfully run are knowing the max brightness and successfully applying
// the max brightness
ASSERT_GT(maxBrightnessNits, 0.f);
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.f, maxBrightnessNits);
+ mWriter->setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.f, maxBrightnessNits);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1030,7 +1031,7 @@
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED()
@@ -1038,7 +1039,7 @@
<< toString(mode);
continue;
}
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1088,7 +1089,7 @@
getDisplayHeight(), PixelFormat::RGBA_8888);
layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()});
layer->setZOrder(10);
- layer->setDataspace(Dataspace::UNKNOWN, mWriter);
+ layer->setDataspace(Dataspace::UNKNOWN, *mWriter);
ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors));
layer->setBlendMode(blendMode);
@@ -1165,14 +1166,14 @@
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED();
return;
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1210,14 +1211,14 @@
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED();
return;
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
@@ -1250,14 +1251,14 @@
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED();
return;
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
@@ -1323,7 +1324,7 @@
getDisplayHeight(), mPixelFormat, mDataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_H);
- mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
std::vector<Color> expectedColors(
static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -1334,14 +1335,14 @@
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED();
return;
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1369,7 +1370,7 @@
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_V);
- mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
std::vector<Color> expectedColors(
static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -1380,14 +1381,14 @@
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED();
return;
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
@@ -1414,7 +1415,7 @@
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::ROT_180);
- mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
+ mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
std::vector<Color> expectedColors(
static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -1426,14 +1427,14 @@
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED();
return;
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ mWriter->presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index ed8a06c..fa66812 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -33,9 +33,11 @@
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <algorithm>
+#include <iterator>
#include <numeric>
#include <string>
#include <thread>
+#include <unordered_map>
#include "GraphicsComposerCallback.h"
#include "VtsComposerClient.h"
@@ -1078,17 +1080,23 @@
}
void execute() {
- const auto& commands = mWriter.getPendingCommands();
- if (commands.empty()) {
- mWriter.reset();
- return;
+ std::vector<CommandResultPayload> payloads;
+ for (auto& [_, writer] : mWriters) {
+ const auto& commands = writer.getPendingCommands();
+ if (commands.empty()) {
+ writer.reset();
+ continue;
+ }
+
+ auto [status, results] = mComposerClient->executeCommands(commands);
+ ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
+ writer.reset();
+
+ payloads.reserve(payloads.size() + results.size());
+ payloads.insert(payloads.end(), std::make_move_iterator(results.begin()),
+ std::make_move_iterator(results.end()));
}
-
- auto [status, results] = mComposerClient->executeCommands(commands);
- ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
-
- mReader.parse(std::move(results));
- mWriter.reset();
+ mReader.parse(std::move(payloads));
}
static inline auto toTimePoint(nsecs_t time) {
@@ -1152,6 +1160,7 @@
const auto& [status, layer] =
mComposerClient->createLayer(display.getDisplayId(), kBufferSlotCount);
EXPECT_TRUE(status.isOk());
+ auto& writer = getWriter(display.getDisplayId());
{
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
ASSERT_NE(nullptr, buffer);
@@ -1160,15 +1169,15 @@
configureLayer(display, layer, Composition::DEVICE, display.getFrameRect(),
display.getCrop());
- mWriter.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
- /*acquireFence*/ -1);
- mWriter.setLayerDataspace(display.getDisplayId(), layer, common::Dataspace::UNKNOWN);
+ writer.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
+ /*acquireFence*/ -1);
+ writer.setLayerDataspace(display.getDisplayId(), layer, common::Dataspace::UNKNOWN);
- mWriter.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
+ writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(display.getDisplayId());
+ writer.presentDisplay(display.getDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
@@ -1177,15 +1186,15 @@
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
ASSERT_NE(nullptr, buffer->handle);
- mWriter.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
- /*acquireFence*/ -1);
- mWriter.setLayerSurfaceDamage(display.getDisplayId(), layer,
- std::vector<Rect>(1, {0, 0, 10, 10}));
- mWriter.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
+ writer.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, buffer->handle,
+ /*acquireFence*/ -1);
+ writer.setLayerSurfaceDamage(display.getDisplayId(), layer,
+ std::vector<Rect>(1, {0, 0, 10, 10}));
+ writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(display.getDisplayId());
+ writer.presentDisplay(display.getDisplayId());
execute();
}
@@ -1194,11 +1203,12 @@
sp<::android::Fence> presentAndGetFence(
std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
- mWriter.validateDisplay(getPrimaryDisplayId(), expectedPresentTime);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.validateDisplay(getPrimaryDisplayId(), expectedPresentTime);
execute();
EXPECT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ writer.presentDisplay(getPrimaryDisplayId());
execute();
EXPECT_TRUE(mReader.takeErrors().empty());
@@ -1230,7 +1240,8 @@
FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
(float)getPrimaryDisplay().getDisplayHeight()};
configureLayer(getPrimaryDisplay(), layer, Composition::DEVICE, displayFrame, cropRect);
- mWriter.setLayerDataspace(getPrimaryDisplayId(), layer, common::Dataspace::UNKNOWN);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerDataspace(getPrimaryDisplayId(), layer, common::Dataspace::UNKNOWN);
return layer;
}
@@ -1330,8 +1341,9 @@
ASSERT_NE(nullptr, buffer2);
const auto layer = createOnScreenLayer();
- mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer1->handle,
- /*acquireFence*/ -1);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer1->handle,
+ /*acquireFence*/ -1);
const sp<::android::Fence> presentFence1 =
presentAndGetFence(ComposerClientWriter::kNoTimestamp);
presentFence1->waitForever(LOG_TAG);
@@ -1341,8 +1353,8 @@
expectedPresentTime += *framesDelay * vsyncPeriod;
}
- mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer2->handle,
- /*acquireFence*/ -1);
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer2->handle,
+ /*acquireFence*/ -1);
const auto setExpectedPresentTime = [&]() -> std::optional<ClockMonotonicTimestamp> {
if (!framesDelay.has_value()) {
return ComposerClientWriter::kNoTimestamp;
@@ -1363,17 +1375,18 @@
void configureLayer(const VtsDisplay& display, int64_t layer, Composition composition,
const Rect& displayFrame, const FRect& cropRect) {
- mWriter.setLayerCompositionType(display.getDisplayId(), layer, composition);
- mWriter.setLayerDisplayFrame(display.getDisplayId(), layer, displayFrame);
- mWriter.setLayerPlaneAlpha(display.getDisplayId(), layer, /*alpha*/ 1);
- mWriter.setLayerSourceCrop(display.getDisplayId(), layer, cropRect);
- mWriter.setLayerTransform(display.getDisplayId(), layer, static_cast<Transform>(0));
- mWriter.setLayerVisibleRegion(display.getDisplayId(), layer,
- std::vector<Rect>(1, displayFrame));
- mWriter.setLayerZOrder(display.getDisplayId(), layer, /*z*/ 10);
- mWriter.setLayerBlendMode(display.getDisplayId(), layer, BlendMode::NONE);
- mWriter.setLayerSurfaceDamage(display.getDisplayId(), layer,
- std::vector<Rect>(1, displayFrame));
+ auto& writer = getWriter(display.getDisplayId());
+ writer.setLayerCompositionType(display.getDisplayId(), layer, composition);
+ writer.setLayerDisplayFrame(display.getDisplayId(), layer, displayFrame);
+ writer.setLayerPlaneAlpha(display.getDisplayId(), layer, /*alpha*/ 1);
+ writer.setLayerSourceCrop(display.getDisplayId(), layer, cropRect);
+ writer.setLayerTransform(display.getDisplayId(), layer, static_cast<Transform>(0));
+ writer.setLayerVisibleRegion(display.getDisplayId(), layer,
+ std::vector<Rect>(1, displayFrame));
+ writer.setLayerZOrder(display.getDisplayId(), layer, /*z*/ 10);
+ writer.setLayerBlendMode(display.getDisplayId(), layer, BlendMode::NONE);
+ writer.setLayerSurfaceDamage(display.getDisplayId(), layer,
+ std::vector<Rect>(1, displayFrame));
}
// clang-format off
const std::array<float, 16> kIdentity = {{
@@ -1384,12 +1397,20 @@
}};
// clang-format on
- ComposerClientWriter mWriter;
+ ComposerClientWriter& getWriter(int64_t display) {
+ auto [it, _] = mWriters.try_emplace(display, display);
+ return it->second;
+ }
+
ComposerClientReader mReader;
+
+ private:
+ std::unordered_map<int64_t, ComposerClientWriter> mWriters;
};
TEST_P(GraphicsComposerAidlCommandTest, SetColorTransform) {
- mWriter.setColorTransform(getPrimaryDisplayId(), kIdentity.data());
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setColorTransform(getPrimaryDisplayId(), kIdentity.data());
execute();
}
@@ -1397,7 +1418,8 @@
const auto& [status, layer] =
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(status.isOk());
- mWriter.setLayerColorTransform(getPrimaryDisplayId(), layer, kIdentity.data());
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerColorTransform(getPrimaryDisplayId(), layer, kIdentity.data());
execute();
const auto errors = mReader.takeErrors();
@@ -1413,8 +1435,9 @@
ASSERT_TRUE(status.isOk());
bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(),
DisplayCapability::BRIGHTNESS) != capabilities.end();
+ auto& writer = getWriter(getPrimaryDisplayId());
if (!brightnessSupport) {
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
+ writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
execute();
const auto errors = mReader.takeErrors();
EXPECT_EQ(1, errors.size());
@@ -1423,23 +1446,23 @@
return;
}
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.0f, -1.f);
+ writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.0f, -1.f);
execute();
EXPECT_TRUE(mReader.takeErrors().empty());
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
+ writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
execute();
EXPECT_TRUE(mReader.takeErrors().empty());
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.0f, -1.f);
+ writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.0f, -1.f);
execute();
EXPECT_TRUE(mReader.takeErrors().empty());
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -1.0f, -1.f);
+ writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -1.0f, -1.f);
execute();
EXPECT_TRUE(mReader.takeErrors().empty());
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 2.0f, -1.f);
+ writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 2.0f, -1.f);
execute();
{
const auto errors = mReader.takeErrors();
@@ -1447,7 +1470,7 @@
EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
}
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -2.0f, -1.f);
+ writer.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -2.0f, -1.f);
execute();
{
const auto errors = mReader.takeErrors();
@@ -1460,8 +1483,9 @@
EXPECT_TRUE(mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kBufferSlotCount)
.isOk());
- mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, nullptr, /*acquireFence*/ -1,
- Dataspace::UNKNOWN, std::vector<Rect>());
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, nullptr, /*acquireFence*/ -1,
+ Dataspace::UNKNOWN, std::vector<Rect>());
execute();
}
@@ -1481,24 +1505,28 @@
const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
const auto handle = buffer->handle;
- mWriter.setOutputBuffer(display.display, /*slot*/ 0, handle, /*releaseFence*/ -1);
+ auto& writer = getWriter(display.display);
+ writer.setOutputBuffer(display.display, /*slot*/ 0, handle, /*releaseFence*/ -1);
execute();
}
TEST_P(GraphicsComposerAidlCommandTest, ValidDisplay) {
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
}
TEST_P(GraphicsComposerAidlCommandTest, AcceptDisplayChanges) {
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
- mWriter.acceptDisplayChanges(getPrimaryDisplayId());
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ writer.acceptDisplayChanges(getPrimaryDisplayId());
execute();
}
TEST_P(GraphicsComposerAidlCommandTest, PresentDisplay) {
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
- mWriter.presentDisplay(getPrimaryDisplayId());
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ writer.presentDisplay(getPrimaryDisplayId());
execute();
}
@@ -1519,6 +1547,7 @@
const auto& [renderIntentsStatus, renderIntents] =
mComposerClient->getRenderIntents(getPrimaryDisplayId(), ColorMode::NATIVE);
EXPECT_TRUE(renderIntentsStatus.isOk());
+ auto& writer = getWriter(getPrimaryDisplayId());
for (auto intent : renderIntents) {
EXPECT_TRUE(mComposerClient->setColorMode(getPrimaryDisplayId(), ColorMode::NATIVE, intent)
.isOk());
@@ -1536,10 +1565,10 @@
FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
(float)getPrimaryDisplay().getDisplayHeight()};
configureLayer(getPrimaryDisplay(), layer, Composition::CURSOR, displayFrame, cropRect);
- mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle,
- /*acquireFence*/ -1);
- mWriter.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle,
+ /*acquireFence*/ -1);
+ writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
+ writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) {
GTEST_SUCCEED() << "Composition change requested, skipping test";
@@ -1547,18 +1576,18 @@
}
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.presentDisplay(getPrimaryDisplayId());
+ writer.presentDisplay(getPrimaryDisplayId());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
const auto buffer2 = allocate(::android::PIXEL_FORMAT_RGBA_8888);
const auto handle2 = buffer2->handle;
ASSERT_NE(nullptr, handle2);
- mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle2,
- /*acquireFence*/ -1);
- mWriter.setLayerSurfaceDamage(getPrimaryDisplayId(), layer,
- std::vector<Rect>(1, {0, 0, 10, 10}));
- mWriter.presentDisplay(getPrimaryDisplayId());
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle2,
+ /*acquireFence*/ -1);
+ writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer,
+ std::vector<Rect>(1, {0, 0, 10, 10}));
+ writer.presentDisplay(getPrimaryDisplayId());
execute();
}
}
@@ -1572,15 +1601,16 @@
const auto handle = buffer->handle;
ASSERT_NE(nullptr, handle);
- mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
Rect displayFrame{0, 0, getPrimaryDisplay().getDisplayWidth(),
getPrimaryDisplay().getDisplayHeight()};
FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
(float)getPrimaryDisplay().getDisplayHeight()};
configureLayer(getPrimaryDisplay(), layer, Composition::CURSOR, displayFrame, cropRect);
- mWriter.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
+ writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
@@ -1588,15 +1618,15 @@
GTEST_SUCCEED() << "Composition change requested, skipping test";
return;
}
- mWriter.presentDisplay(getPrimaryDisplayId());
+ writer.presentDisplay(getPrimaryDisplayId());
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 1, /*y*/ 1);
+ writer.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 1, /*y*/ 1);
execute();
- mWriter.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 0, /*y*/ 0);
- mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
- mWriter.presentDisplay(getPrimaryDisplayId());
+ writer.setLayerCursorPosition(getPrimaryDisplayId(), layer, /*x*/ 0, /*y*/ 0);
+ writer.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
+ writer.presentDisplay(getPrimaryDisplayId());
execute();
}
@@ -1608,7 +1638,8 @@
const auto& [layerStatus, layer] =
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, handle, /*acquireFence*/ -1);
execute();
}
@@ -1620,15 +1651,16 @@
Rect empty{0, 0, 0, 0};
Rect unit{0, 0, 1, 1};
- mWriter.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
+ writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>());
+ writer.setLayerSurfaceDamage(getPrimaryDisplayId(), layer, std::vector<Rect>());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
@@ -1641,15 +1673,16 @@
Rect empty{0, 0, 0, 0};
Rect unit{0, 0, 1, 1};
- mWriter.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
+ writer.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>());
+ writer.setLayerBlockingRegion(getPrimaryDisplayId(), layer, std::vector<Rect>());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
@@ -1659,15 +1692,16 @@
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::NONE);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::NONE);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::PREMULTIPLIED);
+ writer.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::PREMULTIPLIED);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::COVERAGE);
+ writer.setLayerBlendMode(getPrimaryDisplayId(), layer, BlendMode::COVERAGE);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
@@ -1677,11 +1711,12 @@
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerColor(getPrimaryDisplayId(), layer, Color{1.0f, 1.0f, 1.0f, 1.0f});
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerColor(getPrimaryDisplayId(), layer, Color{1.0f, 1.0f, 1.0f, 1.0f});
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerColor(getPrimaryDisplayId(), layer, Color{0.0f, 0.0f, 0.0f, 0.0f});
+ writer.setLayerColor(getPrimaryDisplayId(), layer, Color{0.0f, 0.0f, 0.0f, 0.0f});
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
@@ -1691,19 +1726,20 @@
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CLIENT);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CLIENT);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::DEVICE);
+ writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::DEVICE);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::SOLID_COLOR);
+ writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::SOLID_COLOR);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CURSOR);
+ writer.setLayerCompositionType(getPrimaryDisplayId(), layer, Composition::CURSOR);
execute();
}
@@ -1734,9 +1770,10 @@
configureLayer(display, layer, Composition::DISPLAY_DECORATION, display.getFrameRect(),
display.getCrop());
- mWriter.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, decorBuffer->handle,
- /*acquireFence*/ -1);
- mWriter.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
+ auto& writer = getWriter(display.getDisplayId());
+ writer.setLayerBuffer(display.getDisplayId(), layer, /*slot*/ 0, decorBuffer->handle,
+ /*acquireFence*/ -1);
+ writer.validateDisplay(display.getDisplayId(), ComposerClientWriter::kNoTimestamp);
execute();
if (support) {
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1753,7 +1790,8 @@
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerDataspace(getPrimaryDisplayId(), layer, Dataspace::UNKNOWN);
execute();
}
@@ -1762,7 +1800,8 @@
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerDisplayFrame(getPrimaryDisplayId(), layer, Rect{0, 0, 1, 1});
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerDisplayFrame(getPrimaryDisplayId(), layer, Rect{0, 0, 1, 1});
execute();
}
@@ -1771,11 +1810,12 @@
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 0.0f);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 0.0f);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 1.0f);
+ writer.setLayerPlaneAlpha(getPrimaryDisplayId(), layer, /*alpha*/ 1.0f);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
@@ -1794,7 +1834,8 @@
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerSidebandStream(getPrimaryDisplayId(), layer, handle);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerSidebandStream(getPrimaryDisplayId(), layer, handle);
execute();
}
@@ -1803,7 +1844,8 @@
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerSourceCrop(getPrimaryDisplayId(), layer, FRect{0.0f, 0.0f, 1.0f, 1.0f});
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerSourceCrop(getPrimaryDisplayId(), layer, FRect{0.0f, 0.0f, 1.0f, 1.0f});
execute();
}
@@ -1812,39 +1854,40 @@
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerTransform(getPrimaryDisplayId(), layer, static_cast<Transform>(0));
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerTransform(getPrimaryDisplayId(), layer, static_cast<Transform>(0));
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerTransform(getPrimaryDisplayId(), layer, Transform::FLIP_H);
+ writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::FLIP_H);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerTransform(getPrimaryDisplayId(), layer, Transform::FLIP_V);
+ writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::FLIP_V);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_90);
+ writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_90);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_180);
+ writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_180);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_270);
+ writer.setLayerTransform(getPrimaryDisplayId(), layer, Transform::ROT_270);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerTransform(getPrimaryDisplayId(), layer,
- static_cast<Transform>(static_cast<int>(Transform::FLIP_H) |
- static_cast<int>(Transform::ROT_90)));
+ writer.setLayerTransform(getPrimaryDisplayId(), layer,
+ static_cast<Transform>(static_cast<int>(Transform::FLIP_H) |
+ static_cast<int>(Transform::ROT_90)));
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerTransform(getPrimaryDisplayId(), layer,
- static_cast<Transform>(static_cast<int>(Transform::FLIP_V) |
- static_cast<int>(Transform::ROT_90)));
+ writer.setLayerTransform(getPrimaryDisplayId(), layer,
+ static_cast<Transform>(static_cast<int>(Transform::FLIP_V) |
+ static_cast<int>(Transform::ROT_90)));
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
@@ -1857,15 +1900,16 @@
Rect empty{0, 0, 0, 0};
Rect unit{0, 0, 1, 1};
- mWriter.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, empty));
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
+ writer.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>(1, unit));
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>());
+ writer.setLayerVisibleRegion(getPrimaryDisplayId(), layer, std::vector<Rect>());
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
@@ -1875,11 +1919,12 @@
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(layerStatus.isOk());
- mWriter.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 10);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 10);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 0);
+ writer.setLayerZOrder(getPrimaryDisplayId(), layer, /*z*/ 0);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
}
@@ -1901,6 +1946,7 @@
* white (D65) 0.3127 0.3290
*/
+ auto& writer = getWriter(getPrimaryDisplayId());
std::vector<PerFrameMetadata> aidlMetadata;
aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X, 0.680f});
aidlMetadata.push_back({PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y, 0.320f});
@@ -1914,7 +1960,7 @@
aidlMetadata.push_back({PerFrameMetadataKey::MIN_LUMINANCE, 0.1f});
aidlMetadata.push_back({PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL, 78.0});
aidlMetadata.push_back({PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
- mWriter.setLayerPerFrameMetadata(getPrimaryDisplayId(), layer, aidlMetadata);
+ writer.setLayerPerFrameMetadata(getPrimaryDisplayId(), layer, aidlMetadata);
execute();
const auto errors = mReader.takeErrors();
@@ -1931,19 +1977,20 @@
const auto& [layerStatus, layer] =
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
- mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 0.2f);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerBrightness(getPrimaryDisplayId(), layer, 0.2f);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 1.f);
+ writer.setLayerBrightness(getPrimaryDisplayId(), layer, 1.f);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, 0.f);
+ writer.setLayerBrightness(getPrimaryDisplayId(), layer, 0.f);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
- mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, -1.f);
+ writer.setLayerBrightness(getPrimaryDisplayId(), layer, -1.f);
execute();
{
const auto errors = mReader.takeErrors();
@@ -1951,7 +1998,7 @@
EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
}
- mWriter.setLayerBrightness(getPrimaryDisplayId(), layer, std::nanf(""));
+ writer.setLayerBrightness(getPrimaryDisplayId(), layer, std::nanf(""));
execute();
{
const auto errors = mReader.takeErrors();
@@ -2116,8 +2163,9 @@
ASSERT_NE(nullptr, buffer->handle);
const auto layer = createOnScreenLayer();
- mWriter.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer->handle,
- /*acquireFence*/ -1);
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer->handle,
+ /*acquireFence*/ -1);
int32_t vsyncIdleCount = mComposerClient->getVsyncIdleCount();
auto earlyVsyncIdleTime = systemTime() + std::chrono::nanoseconds(2s).count();
EXPECT_TRUE(
diff --git a/graphics/mapper/stable-c/Android.bp b/graphics/mapper/stable-c/Android.bp
new file mode 100644
index 0000000..c03f67e
--- /dev/null
+++ b/graphics/mapper/stable-c/Android.bp
@@ -0,0 +1,104 @@
+/**
+ * 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 {
+ // 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"],
+}
+
+cc_library_headers {
+ name: "libimapper_stablec",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+ header_libs: [
+ "libarect_headers",
+ ],
+ export_header_lib_headers: [
+ "libarect_headers",
+ ],
+}
+
+cc_library_headers {
+ name: "libimapper_providerutils",
+ vendor_available: true,
+ export_include_dirs: ["implutils/include"],
+ header_libs: [
+ "libbase_headers",
+ "libimapper_stablec",
+ ],
+ export_header_lib_headers: [
+ "libbase_headers",
+ "libimapper_stablec",
+ ],
+}
+
+cc_test {
+ name: "libimapper_providerutils_tests",
+ defaults: [
+ "android.hardware.graphics.allocator-ndk_shared",
+ "android.hardware.graphics.common-ndk_shared",
+ ],
+ header_libs: [
+ "libimapper_providerutils",
+ ],
+ srcs: [
+ "implutils/impltests.cpp",
+ ],
+ visibility: [":__subpackages__"],
+ cpp_std: "experimental",
+}
+
+cc_test {
+ name: "VtsHalGraphicsMapperStableC_TargetTest",
+ cpp_std: "experimental",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ "android.hardware.graphics.allocator-ndk_shared",
+ "android.hardware.graphics.common-ndk_shared",
+ ],
+ srcs: [
+ "vts/VtsHalGraphicsMapperStableC_TargetTest.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder_ndk",
+ "libbase",
+ "libsync",
+ "libvndksupport",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ "libgralloctypes",
+ "libgtest",
+ ],
+ header_libs: [
+ "libimapper_stablec",
+ "libimapper_providerutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/graphics/mapper/stable-c/implutils/impltests.cpp b/graphics/mapper/stable-c/implutils/impltests.cpp
new file mode 100644
index 0000000..9c5d70b
--- /dev/null
+++ b/graphics/mapper/stable-c/implutils/impltests.cpp
@@ -0,0 +1,314 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
+#include <android/hardware/graphics/mapper/utils/IMapperProvider.h>
+#include <vector>
+
+using namespace ::android::hardware::graphics::mapper;
+using namespace ::aidl::android::hardware::graphics::common;
+
+// These tests are primarily interested in hitting all the different *types* that can be
+// serialized/deserialized than in exhaustively testing all the StandardMetadataTypes.
+// Exhaustive testing of the actual metadata types is relegated for IMapper's VTS suite
+// where meaning & correctness of values are more narrowly defined (eg, read-only values)
+
+TEST(Metadata, setGetBufferId) {
+ using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
+
+ std::vector<char> buffer;
+ buffer.resize(12, 0);
+ *reinterpret_cast<int64_t*>(buffer.data()) = 42;
+
+ EXPECT_EQ(8, BufferId::encode(18, buffer.data(), 0));
+ EXPECT_EQ(42, *reinterpret_cast<int64_t*>(buffer.data()));
+ EXPECT_EQ(8, BufferId::encode(18, buffer.data(), buffer.size()));
+ EXPECT_EQ(18, *reinterpret_cast<int64_t*>(buffer.data()));
+ EXPECT_FALSE(BufferId::decode(buffer.data(), 0));
+ auto read = BufferId::decode(buffer.data(), buffer.size());
+ EXPECT_TRUE(read.has_value());
+ EXPECT_EQ(18, read.value_or(0));
+}
+
+TEST(Metadata, setGetDataspace) {
+ using DataspaceValue = StandardMetadata<StandardMetadataType::DATASPACE>::value;
+ using intType = std::underlying_type_t<Dataspace>;
+ std::vector<char> buffer;
+ buffer.resize(12, 0);
+
+ EXPECT_EQ(4, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), 0));
+ EXPECT_EQ(0, *reinterpret_cast<intType*>(buffer.data()));
+ EXPECT_EQ(4, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), buffer.size()));
+ EXPECT_EQ(static_cast<intType>(Dataspace::BT2020), *reinterpret_cast<intType*>(buffer.data()));
+ EXPECT_FALSE(DataspaceValue::decode(buffer.data(), 0));
+ auto read = DataspaceValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(Dataspace::BT2020, *read);
+}
+
+TEST(Metadata, setGetValidName) {
+ using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+
+ std::vector<char> buffer;
+ buffer.resize(100, 'a');
+ buffer[buffer.size() - 1] = '\0';
+
+ // len("Hello") + sizeof(int64)
+ constexpr int expectedSize = 5 + sizeof(int64_t);
+ EXPECT_EQ(expectedSize, NameValue::encode("Hello", buffer.data(), buffer.size()));
+ EXPECT_EQ(5, *reinterpret_cast<int64_t*>(buffer.data()));
+ // Verify didn't write past the end of the desired size
+ EXPECT_EQ('a', buffer[expectedSize]);
+
+ auto readValue = NameValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(readValue.has_value());
+ EXPECT_EQ(5, readValue->length());
+ EXPECT_EQ("Hello", *readValue);
+}
+
+TEST(Metadata, setGetInvalidName) {
+ using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+
+ std::vector<char> buffer;
+ buffer.resize(12, 'a');
+ buffer[buffer.size() - 1] = '\0';
+
+ // len("This is a long string") + sizeof(int64)
+ constexpr int expectedSize = 21 + sizeof(int64_t);
+ EXPECT_EQ(expectedSize,
+ NameValue::encode("This is a long string", buffer.data(), buffer.size()));
+ EXPECT_EQ(21, *reinterpret_cast<int64_t*>(buffer.data()));
+ // Verify didn't write the too-long string
+ EXPECT_EQ('a', buffer[9]);
+ EXPECT_EQ('\0', buffer[buffer.size() - 1]);
+
+ auto readValue = NameValue::decode(buffer.data(), buffer.size());
+ EXPECT_FALSE(readValue.has_value());
+ readValue = NameValue::decode(buffer.data(), 0);
+ ASSERT_FALSE(readValue.has_value());
+}
+
+TEST(Metadata, wouldOverflowName) {
+ using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
+ std::vector<char> buffer(100, 0);
+
+ // int_max + sizeof(int64) overflows int32
+ std::string_view bad_string{"badbeef", std::numeric_limits<int32_t>::max()};
+ EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
+ NameValue::encode(bad_string, buffer.data(), buffer.size()));
+
+ // check barely overflows
+ bad_string = std::string_view{"badbeef", std::numeric_limits<int32_t>::max() - 7};
+ EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
+ NameValue::encode(bad_string, buffer.data(), buffer.size()));
+}
+
+TEST(Metadata, setGetCompression) {
+ using CompressionValue = StandardMetadata<StandardMetadataType::COMPRESSION>::value;
+ ExtendableType myCompression{"bestest_compression_ever", 42};
+ std::vector<char> buffer(100, '\0');
+ const int expectedSize = myCompression.name.length() + sizeof(int64_t) + sizeof(int64_t);
+ EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), 0));
+ EXPECT_EQ(0, buffer[0]);
+ EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), buffer.size()));
+ EXPECT_EQ(myCompression.name.length(), *reinterpret_cast<int64_t*>(buffer.data()));
+ EXPECT_FALSE(CompressionValue::decode(buffer.data(), 0).has_value());
+ auto read = CompressionValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(myCompression, read.value());
+}
+
+TEST(Metadata, setGetPlaneLayout) {
+ using PlaneLayoutValue = StandardMetadata<StandardMetadataType::PLANE_LAYOUTS>::value;
+ PlaneLayout myPlaneLayout;
+ myPlaneLayout.offsetInBytes = 10;
+ myPlaneLayout.sampleIncrementInBits = 11;
+ myPlaneLayout.strideInBytes = 12;
+ myPlaneLayout.widthInSamples = 13;
+ myPlaneLayout.heightInSamples = 14;
+ myPlaneLayout.totalSizeInBytes = 15;
+ myPlaneLayout.horizontalSubsampling = 16;
+ myPlaneLayout.verticalSubsampling = 17;
+
+ myPlaneLayout.components.resize(3);
+ for (int i = 0; i < myPlaneLayout.components.size(); i++) {
+ auto& it = myPlaneLayout.components[i];
+ it.type = ExtendableType{"Plane ID", 40 + i};
+ it.offsetInBits = 20 + i;
+ it.sizeInBits = 30 + i;
+ }
+
+ std::vector<PlaneLayout> layouts{myPlaneLayout, PlaneLayout{}};
+
+ std::vector<char> buffer(5000, '\0');
+ constexpr int componentSize = 8 + (4 * sizeof(int64_t));
+ constexpr int firstLayoutSize = (8 + 1) * sizeof(int64_t) + (3 * componentSize);
+ constexpr int secondLayoutSize = (8 + 1) * sizeof(int64_t);
+ constexpr int expectedSize = firstLayoutSize + secondLayoutSize + sizeof(int64_t);
+ EXPECT_EQ(expectedSize, PlaneLayoutValue::encode(layouts, buffer.data(), 0));
+ EXPECT_EQ(0, buffer[0]);
+ EXPECT_EQ(expectedSize, PlaneLayoutValue::encode(layouts, buffer.data(), buffer.size()));
+ EXPECT_EQ(3, reinterpret_cast<int64_t*>(buffer.data())[1]);
+ EXPECT_EQ(8, reinterpret_cast<int64_t*>(buffer.data())[2]);
+ EXPECT_EQ(40, reinterpret_cast<int64_t*>(buffer.data())[4]);
+ EXPECT_EQ(31, reinterpret_cast<int64_t*>(buffer.data())[11]);
+ EXPECT_EQ(22, reinterpret_cast<int64_t*>(buffer.data())[15]);
+ EXPECT_EQ(10, reinterpret_cast<int64_t*>(buffer.data())[17]);
+ EXPECT_EQ(11, reinterpret_cast<int64_t*>(buffer.data())[18]);
+ EXPECT_FALSE(PlaneLayoutValue::decode(buffer.data(), 0).has_value());
+ auto read = PlaneLayoutValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(layouts, *read);
+}
+
+TEST(Metadata, setGetRects) {
+ using RectsValue = StandardMetadata<StandardMetadataType::CROP>::value;
+ std::vector<uint8_t> buffer(500, 0);
+ std::vector<Rect> cropRects{2};
+ cropRects[0] = Rect{10, 11, 12, 13};
+ cropRects[1] = Rect{20, 21, 22, 23};
+
+ constexpr int expectedSize = sizeof(int64_t) + (8 * sizeof(int32_t));
+ EXPECT_EQ(expectedSize, RectsValue::encode(cropRects, buffer.data(), buffer.size()));
+ EXPECT_EQ(2, reinterpret_cast<int64_t*>(buffer.data())[0]);
+ EXPECT_EQ(10, reinterpret_cast<int32_t*>(buffer.data())[2]);
+ auto read = RectsValue::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ EXPECT_EQ(cropRects.size(), read->size());
+ EXPECT_EQ(cropRects, *read);
+}
+
+TEST(Metadata, setGetSmpte2086) {
+ using Smpte2086Value = StandardMetadata<StandardMetadataType::SMPTE2086>::value;
+ Smpte2086 source;
+ source.minLuminance = 12.335f;
+ source.maxLuminance = 452.889f;
+ source.whitePoint = XyColor{-6.f, -9.f};
+ source.primaryRed = XyColor{.1f, .2f};
+ source.primaryGreen = XyColor{.3f, .4f};
+ source.primaryBlue = XyColor{.5f, .6f};
+
+ constexpr int expectedSize = 10 * sizeof(float);
+ std::vector<uint8_t> buffer(500, 0);
+ EXPECT_EQ(expectedSize, Smpte2086Value::encode(source, buffer.data(), buffer.size()));
+ auto read = Smpte2086Value::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ ASSERT_TRUE(read->has_value());
+ EXPECT_EQ(source, read->value());
+
+ // A valid encoding of a nullopt
+ read = Smpte2086Value::decode(nullptr, 0);
+ ASSERT_TRUE(read.has_value());
+ EXPECT_FALSE(read->has_value());
+}
+
+TEST(Metadata, setGetCta861_3) {
+ using Cta861_3Value = StandardMetadata<StandardMetadataType::CTA861_3>::value;
+ Cta861_3 source;
+ source.maxFrameAverageLightLevel = 244.55f;
+ source.maxContentLightLevel = 202.202f;
+
+ constexpr int expectedSize = 2 * sizeof(float);
+ std::vector<uint8_t> buffer(500, 0);
+ EXPECT_EQ(expectedSize, Cta861_3Value::encode(source, buffer.data(), buffer.size()));
+ auto read = Cta861_3Value::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ ASSERT_TRUE(read->has_value());
+ EXPECT_EQ(source, read->value());
+
+ // A valid encoding of a nullopt
+ read = Cta861_3Value::decode(nullptr, 0);
+ ASSERT_TRUE(read.has_value());
+ EXPECT_FALSE(read->has_value());
+}
+
+TEST(Metadata, setGetSmpte2094_10) {
+ using SMPTE2094_10Value = StandardMetadata<StandardMetadataType::SMPTE2094_10>::value;
+
+ std::vector<uint8_t> buffer(500, 0);
+ EXPECT_EQ(0, SMPTE2094_10Value::encode(std::nullopt, buffer.data(), buffer.size()));
+ auto read = SMPTE2094_10Value::decode(buffer.data(), 0);
+ ASSERT_TRUE(read.has_value());
+ EXPECT_FALSE(read->has_value());
+
+ const std::vector<uint8_t> emptyBuffer;
+ EXPECT_EQ(sizeof(int64_t),
+ SMPTE2094_10Value::encode(emptyBuffer, buffer.data(), buffer.size()));
+ read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ ASSERT_TRUE(read->has_value());
+ EXPECT_EQ(0, read->value().size());
+
+ const std::vector<uint8_t> simpleBuffer{0, 1, 2, 3, 4, 5};
+ EXPECT_EQ(sizeof(int64_t) + 6,
+ SMPTE2094_10Value::encode(simpleBuffer, buffer.data(), buffer.size()));
+ read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
+ ASSERT_TRUE(read.has_value());
+ ASSERT_TRUE(read->has_value());
+ EXPECT_EQ(6, read->value().size());
+ EXPECT_EQ(simpleBuffer, read->value());
+}
+
+TEST(MetadataProvider, bufferId) {
+ using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
+ std::vector<uint8_t> buffer(500, 0);
+ int result = provideStandardMetadata(StandardMetadataType::BUFFER_ID, buffer.data(),
+ buffer.size(), []<StandardMetadataType T>(auto&& provide) {
+ if constexpr (T == StandardMetadataType::BUFFER_ID) {
+ return provide(42);
+ }
+ return 0;
+ });
+
+ EXPECT_EQ(8, result);
+ auto read = BufferId::decode(buffer.data(), buffer.size());
+ EXPECT_EQ(42, read.value_or(0));
+}
+
+TEST(MetadataProvider, allJumpsWork) {
+ const auto& values = ndk::internal::enum_values<StandardMetadataType>;
+ auto get = [](StandardMetadataType type) -> int {
+ return provideStandardMetadata(type, nullptr, 0, []<StandardMetadataType T>(auto&&) {
+ return static_cast<int>(T) + 100;
+ });
+ };
+
+ for (auto& type : values) {
+ const int expected = type == StandardMetadataType::INVALID ? -AIMAPPER_ERROR_UNSUPPORTED
+ : static_cast<int>(type) + 100;
+ EXPECT_EQ(expected, get(type));
+ }
+}
+
+TEST(MetadataProvider, invalid) {
+ int result = provideStandardMetadata(StandardMetadataType::INVALID, nullptr, 0,
+ []<StandardMetadataType T>(auto&&) { return 10; });
+
+ EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result);
+}
+
+TEST(MetadataProvider, outOfBounds) {
+ int result = provideStandardMetadata(static_cast<StandardMetadataType>(-1), nullptr, 0,
+ []<StandardMetadataType T>(auto&&) { return 10; });
+ EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result) << "-1 should have resulted in UNSUPPORTED";
+
+ result = provideStandardMetadata(static_cast<StandardMetadataType>(100), nullptr, 0,
+ []<StandardMetadataType T>(auto&&) { return 10; });
+ EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result)
+ << "100 (out of range) should have resulted in UNSUPPORTED";
+}
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
new file mode 100644
index 0000000..7861af8
--- /dev/null
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
@@ -0,0 +1,576 @@
+/*
+ * 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 <aidl/android/hardware/graphics/common/BlendMode.h>
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/Cta861_3.h>
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+#include <aidl/android/hardware/graphics/common/ExtendableType.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponent.h>
+#include <aidl/android/hardware/graphics/common/Rect.h>
+#include <aidl/android/hardware/graphics/common/Smpte2086.h>
+#include <aidl/android/hardware/graphics/common/StandardMetadataType.h>
+#include <aidl/android/hardware/graphics/common/XyColor.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+
+#include <cinttypes>
+#include <string_view>
+#include <type_traits>
+#include <vector>
+
+namespace android::hardware::graphics::mapper {
+
+using ::aidl::android::hardware::graphics::common::BlendMode;
+using ::aidl::android::hardware::graphics::common::BufferUsage;
+using ::aidl::android::hardware::graphics::common::Cta861_3;
+using ::aidl::android::hardware::graphics::common::Dataspace;
+using ::aidl::android::hardware::graphics::common::ExtendableType;
+using ::aidl::android::hardware::graphics::common::PixelFormat;
+using ::aidl::android::hardware::graphics::common::PlaneLayout;
+using ::aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using ::aidl::android::hardware::graphics::common::Rect;
+using ::aidl::android::hardware::graphics::common::Smpte2086;
+using ::aidl::android::hardware::graphics::common::StandardMetadataType;
+using ::aidl::android::hardware::graphics::common::XyColor;
+
+class MetadataWriter {
+ private:
+ uint8_t* _Nonnull mDest;
+ size_t mSizeRemaining = 0;
+ int32_t mDesiredSize = 0;
+
+ void* _Nullable reserve(size_t sizeToWrite) {
+ if (mDesiredSize < 0) {
+ // Error state
+ return nullptr;
+ }
+ if (__builtin_add_overflow(mDesiredSize, sizeToWrite, &mDesiredSize)) {
+ // Overflowed, abort writing any further data
+ mDesiredSize = -AIMAPPER_ERROR_BAD_VALUE;
+ mSizeRemaining = 0;
+ return nullptr;
+ }
+ if (sizeToWrite > mSizeRemaining) {
+ mSizeRemaining = 0;
+ return nullptr;
+ } else {
+ mSizeRemaining -= sizeToWrite;
+ uint8_t* whereToWrite = mDest;
+ mDest += sizeToWrite;
+ return whereToWrite;
+ }
+ }
+
+ public:
+ explicit MetadataWriter(void* _Nullable destBuffer, size_t destBufferSize)
+ : mDest(reinterpret_cast<uint8_t*>(destBuffer)), mSizeRemaining(destBufferSize) {}
+
+ int32_t desiredSize() const { return mDesiredSize; }
+
+ template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+ MetadataWriter& write(T value) {
+ auto sizeToWrite = sizeof(T);
+ if (void* dest = reserve(sizeToWrite)) {
+ memcpy(dest, &value, sizeToWrite);
+ }
+ return *this;
+ }
+
+ MetadataWriter& write(float value) {
+ auto sizeToWrite = sizeof(float);
+ if (void* dest = reserve(sizeToWrite)) {
+ memcpy(dest, &value, sizeToWrite);
+ }
+ return *this;
+ }
+
+ MetadataWriter& write(const std::string_view& value) {
+ auto sizeToWrite = value.length();
+ write<int64_t>(sizeToWrite);
+ if (void* dest = reserve(sizeToWrite)) {
+ memcpy(dest, value.data(), sizeToWrite);
+ }
+ return *this;
+ }
+
+ MetadataWriter& write(const std::vector<uint8_t>& value) {
+ auto sizeToWrite = value.size();
+ write<int64_t>(sizeToWrite);
+ if (void* dest = reserve(sizeToWrite)) {
+ memcpy(dest, value.data(), sizeToWrite);
+ }
+ return *this;
+ }
+
+ MetadataWriter& write(const ExtendableType& value) {
+ return write(value.name).write(value.value);
+ }
+
+ MetadataWriter& write(const XyColor& value) { return write(value.x).write(value.y); }
+};
+
+class MetadataReader {
+ private:
+ const uint8_t* _Nonnull mSrc;
+ size_t mSizeRemaining = 0;
+ bool mOk = true;
+
+ const void* _Nullable advance(size_t size) {
+ if (mOk && mSizeRemaining >= size) {
+ const void* buf = mSrc;
+ mSrc += size;
+ mSizeRemaining -= size;
+ return buf;
+ }
+ mOk = false;
+ return nullptr;
+ }
+
+ public:
+ explicit MetadataReader(const void* _Nonnull metadata, size_t metadataSize)
+ : mSrc(reinterpret_cast<const uint8_t*>(metadata)), mSizeRemaining(metadataSize) {}
+
+ [[nodiscard]] size_t remaining() const { return mSizeRemaining; }
+ [[nodiscard]] bool ok() const { return mOk; }
+
+ template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+ MetadataReader& read(T& dest) {
+ if (const void* src = advance(sizeof(T))) {
+ memcpy(&dest, src, sizeof(T));
+ }
+ return *this;
+ }
+
+ MetadataReader& read(float& dest) {
+ if (const void* src = advance(sizeof(float))) {
+ memcpy(&dest, src, sizeof(float));
+ }
+ return *this;
+ }
+
+ MetadataReader& read(std::string& dest) {
+ dest = readString();
+ return *this;
+ }
+
+ MetadataReader& read(ExtendableType& dest) {
+ dest.name = readString();
+ read(dest.value);
+ return *this;
+ }
+
+ MetadataReader& read(XyColor& dest) {
+ read(dest.x);
+ read(dest.y);
+ return *this;
+ }
+
+ template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
+ [[nodiscard]] std::optional<T> readInt() {
+ auto sizeToRead = sizeof(T);
+ if (const void* src = advance(sizeof(T))) {
+ T ret;
+ memcpy(&ret, src, sizeToRead);
+ return ret;
+ }
+ return std::nullopt;
+ }
+
+ [[nodiscard]] std::string_view readString() {
+ auto lengthOpt = readInt<int64_t>();
+ if (!lengthOpt) {
+ return std::string_view{};
+ }
+ size_t length = lengthOpt.value();
+ if (const void* src = advance(length)) {
+ return std::string_view{reinterpret_cast<const char*>(src), length};
+ }
+ return std::string_view{};
+ }
+
+ [[nodiscard]] std::optional<ExtendableType> readExtendable() {
+ ExtendableType ret;
+ ret.name = readString();
+ auto value = readInt<int64_t>();
+ if (value) {
+ ret.value = value.value();
+ return ret;
+ } else {
+ return std::nullopt;
+ }
+ }
+
+ [[nodiscard]] std::vector<uint8_t> readBuffer() {
+ std::vector<uint8_t> ret;
+ size_t length = readInt<int64_t>().value_or(0);
+ if (const void* src = advance(length)) {
+ ret.resize(length);
+ memcpy(ret.data(), src, length);
+ }
+ return ret;
+ }
+};
+
+template <typename T, class Enable = void>
+struct MetadataValue {};
+
+template <typename T>
+struct MetadataValue<T, std::enable_if_t<std::is_integral_v<T>>> {
+ [[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
+ size_t destBufferSize) {
+ return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+ }
+
+ [[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
+ size_t metadataSize) {
+ return MetadataReader{metadata, metadataSize}.readInt<T>();
+ }
+};
+
+template <typename T>
+struct MetadataValue<T, std::enable_if_t<std::is_enum_v<T>>> {
+ [[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
+ size_t destBufferSize) {
+ return MetadataWriter{destBuffer, destBufferSize}
+ .write(static_cast<std::underlying_type_t<T>>(value))
+ .desiredSize();
+ }
+
+ [[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
+ size_t metadataSize) {
+ std::underlying_type_t<T> temp;
+ return MetadataReader{metadata, metadataSize}.read(temp).ok()
+ ? std::optional<T>(static_cast<T>(temp))
+ : std::nullopt;
+ }
+};
+
+template <>
+struct MetadataValue<std::string> {
+ [[nodiscard]] static int32_t encode(const std::string_view& value, void* _Nullable destBuffer,
+ size_t destBufferSize) {
+ return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+ }
+
+ [[nodiscard]] static std::optional<std::string> decode(const void* _Nonnull metadata,
+ size_t metadataSize) {
+ auto reader = MetadataReader{metadata, metadataSize};
+ auto result = reader.readString();
+ return reader.ok() ? std::optional<std::string>{result} : std::nullopt;
+ }
+};
+
+template <>
+struct MetadataValue<ExtendableType> {
+ static_assert(sizeof(int64_t) == sizeof(ExtendableType::value));
+
+ [[nodiscard]] static int32_t encode(const ExtendableType& value, void* _Nullable destBuffer,
+ size_t destBufferSize) {
+ return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
+ }
+
+ [[nodiscard]] static std::optional<ExtendableType> decode(const void* _Nonnull metadata,
+ size_t metadataSize) {
+ return MetadataReader{metadata, metadataSize}.readExtendable();
+ }
+};
+
+template <>
+struct MetadataValue<std::vector<PlaneLayout>> {
+ [[nodiscard]] static int32_t encode(const std::vector<PlaneLayout>& values,
+ void* _Nullable destBuffer, size_t destBufferSize) {
+ MetadataWriter writer{destBuffer, destBufferSize};
+ writer.write<int64_t>(values.size());
+ for (const auto& value : values) {
+ writer.write<int64_t>(value.components.size());
+ for (const auto& component : value.components) {
+ writer.write(component.type)
+ .write<int64_t>(component.offsetInBits)
+ .write<int64_t>(component.sizeInBits);
+ }
+ writer.write<int64_t>(value.offsetInBytes)
+ .write<int64_t>(value.sampleIncrementInBits)
+ .write<int64_t>(value.strideInBytes)
+ .write<int64_t>(value.widthInSamples)
+ .write<int64_t>(value.heightInSamples)
+ .write<int64_t>(value.totalSizeInBytes)
+ .write<int64_t>(value.horizontalSubsampling)
+ .write<int64_t>(value.verticalSubsampling);
+ }
+ return writer.desiredSize();
+ }
+
+ using DecodeResult = std::optional<std::vector<PlaneLayout>>;
+ [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
+ std::vector<PlaneLayout> values;
+ MetadataReader reader{metadata, metadataSize};
+ auto numPlanes = reader.readInt<int64_t>().value_or(0);
+ values.reserve(numPlanes);
+ for (int i = 0; i < numPlanes && reader.ok(); i++) {
+ PlaneLayout& value = values.emplace_back();
+ auto numPlaneComponents = reader.readInt<int64_t>().value_or(0);
+ value.components.reserve(numPlaneComponents);
+ for (int i = 0; i < numPlaneComponents && reader.ok(); i++) {
+ PlaneLayoutComponent& component = value.components.emplace_back();
+ reader.read(component.type)
+ .read<int64_t>(component.offsetInBits)
+ .read<int64_t>(component.sizeInBits);
+ }
+ reader.read<int64_t>(value.offsetInBytes)
+ .read<int64_t>(value.sampleIncrementInBits)
+ .read<int64_t>(value.strideInBytes)
+ .read<int64_t>(value.widthInSamples)
+ .read<int64_t>(value.heightInSamples)
+ .read<int64_t>(value.totalSizeInBytes)
+ .read<int64_t>(value.horizontalSubsampling)
+ .read<int64_t>(value.verticalSubsampling);
+ }
+ return reader.ok() ? DecodeResult{std::move(values)} : std::nullopt;
+ }
+};
+
+template <>
+struct MetadataValue<std::vector<Rect>> {
+ [[nodiscard]] static int32_t encode(const std::vector<Rect>& value, void* _Nullable destBuffer,
+ size_t destBufferSize) {
+ MetadataWriter writer{destBuffer, destBufferSize};
+ writer.write<int64_t>(value.size());
+ for (auto& rect : value) {
+ writer.write<int32_t>(rect.left)
+ .write<int32_t>(rect.top)
+ .write<int32_t>(rect.right)
+ .write<int32_t>(rect.bottom);
+ }
+ return writer.desiredSize();
+ }
+
+ using DecodeResult = std::optional<std::vector<Rect>>;
+ [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
+ MetadataReader reader{metadata, metadataSize};
+ std::vector<Rect> value;
+ auto numRects = reader.readInt<int64_t>().value_or(0);
+ value.reserve(numRects);
+ for (int i = 0; i < numRects && reader.ok(); i++) {
+ Rect& rect = value.emplace_back();
+ reader.read<int32_t>(rect.left)
+ .read<int32_t>(rect.top)
+ .read<int32_t>(rect.right)
+ .read<int32_t>(rect.bottom);
+ }
+ return reader.ok() ? DecodeResult{std::move(value)} : std::nullopt;
+ }
+};
+
+template <>
+struct MetadataValue<std::optional<Smpte2086>> {
+ [[nodiscard]] static int32_t encode(const std::optional<Smpte2086>& optValue,
+ void* _Nullable destBuffer, size_t destBufferSize) {
+ if (optValue.has_value()) {
+ const auto& value = *optValue;
+ return MetadataWriter{destBuffer, destBufferSize}
+ .write(value.primaryRed)
+ .write(value.primaryGreen)
+ .write(value.primaryBlue)
+ .write(value.whitePoint)
+ .write(value.maxLuminance)
+ .write(value.minLuminance)
+ .desiredSize();
+ } else {
+ return 0;
+ }
+ }
+
+ // Double optional because the value type itself is an optional<>
+ using DecodeResult = std::optional<std::optional<Smpte2086>>;
+ [[nodiscard]] static DecodeResult decode(const void* _Nullable metadata, size_t metadataSize) {
+ std::optional<Smpte2086> optValue{std::nullopt};
+ if (metadataSize > 0) {
+ Smpte2086 value;
+ MetadataReader reader{metadata, metadataSize};
+ reader.read(value.primaryRed)
+ .read(value.primaryGreen)
+ .read(value.primaryBlue)
+ .read(value.whitePoint)
+ .read(value.maxLuminance)
+ .read(value.minLuminance);
+ if (reader.ok()) {
+ optValue = std::move(value);
+ } else {
+ return std::nullopt;
+ }
+ }
+ return DecodeResult{std::move(optValue)};
+ }
+};
+
+template <>
+struct MetadataValue<std::optional<Cta861_3>> {
+ [[nodiscard]] static int32_t encode(const std::optional<Cta861_3>& optValue,
+ void* _Nullable destBuffer, size_t destBufferSize) {
+ if (optValue.has_value()) {
+ const auto& value = *optValue;
+ return MetadataWriter{destBuffer, destBufferSize}
+ .write(value.maxContentLightLevel)
+ .write(value.maxFrameAverageLightLevel)
+ .desiredSize();
+ } else {
+ return 0;
+ }
+ }
+
+ // Double optional because the value type itself is an optional<>
+ using DecodeResult = std::optional<std::optional<Cta861_3>>;
+ [[nodiscard]] static DecodeResult decode(const void* _Nullable metadata, size_t metadataSize) {
+ std::optional<Cta861_3> optValue{std::nullopt};
+ if (metadataSize > 0) {
+ MetadataReader reader{metadata, metadataSize};
+ Cta861_3 value;
+ reader.read(value.maxContentLightLevel).read(value.maxFrameAverageLightLevel);
+ if (reader.ok()) {
+ optValue = std::move(value);
+ } else {
+ return std::nullopt;
+ }
+ }
+ return DecodeResult{std::move(optValue)};
+ }
+};
+
+template <>
+struct MetadataValue<std::optional<std::vector<uint8_t>>> {
+ [[nodiscard]] static int32_t encode(const std::optional<std::vector<uint8_t>>& value,
+ void* _Nullable destBuffer, size_t destBufferSize) {
+ if (!value.has_value()) {
+ return 0;
+ }
+ return MetadataWriter{destBuffer, destBufferSize}.write(*value).desiredSize();
+ }
+
+ using DecodeResult = std::optional<std::optional<std::vector<uint8_t>>>;
+ [[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
+ std::optional<std::vector<uint8_t>> optValue;
+ if (metadataSize > 0) {
+ MetadataReader reader{metadata, metadataSize};
+ auto value = reader.readBuffer();
+ if (reader.ok()) {
+ optValue = std::move(value);
+ } else {
+ return std::nullopt;
+ }
+ }
+ return DecodeResult{std::move(optValue)};
+ }
+};
+
+template <StandardMetadataType>
+struct StandardMetadata {};
+
+#define DEFINE_TYPE(name, typeArg) \
+ template <> \
+ struct StandardMetadata<StandardMetadataType::name> { \
+ using value_type = typeArg; \
+ using value = MetadataValue<value_type>; \
+ static_assert( \
+ StandardMetadataType::name == \
+ ndk::internal::enum_values<StandardMetadataType>[static_cast<size_t>( \
+ StandardMetadataType::name)], \
+ "StandardMetadataType must have equivalent value to index"); \
+ }
+
+DEFINE_TYPE(BUFFER_ID, uint64_t);
+DEFINE_TYPE(NAME, std::string);
+DEFINE_TYPE(WIDTH, uint64_t);
+DEFINE_TYPE(HEIGHT, uint64_t);
+DEFINE_TYPE(LAYER_COUNT, uint64_t);
+DEFINE_TYPE(PIXEL_FORMAT_REQUESTED, PixelFormat);
+DEFINE_TYPE(PIXEL_FORMAT_FOURCC, uint32_t);
+DEFINE_TYPE(PIXEL_FORMAT_MODIFIER, uint64_t);
+DEFINE_TYPE(USAGE, BufferUsage);
+DEFINE_TYPE(ALLOCATION_SIZE, uint64_t);
+DEFINE_TYPE(PROTECTED_CONTENT, uint64_t);
+DEFINE_TYPE(COMPRESSION, ExtendableType);
+DEFINE_TYPE(INTERLACED, ExtendableType);
+DEFINE_TYPE(CHROMA_SITING, ExtendableType);
+DEFINE_TYPE(PLANE_LAYOUTS, std::vector<PlaneLayout>);
+DEFINE_TYPE(CROP, std::vector<Rect>);
+DEFINE_TYPE(DATASPACE, Dataspace);
+DEFINE_TYPE(BLEND_MODE, BlendMode);
+DEFINE_TYPE(SMPTE2086, std::optional<Smpte2086>);
+DEFINE_TYPE(CTA861_3, std::optional<Cta861_3>);
+DEFINE_TYPE(SMPTE2094_10, std::optional<std::vector<uint8_t>>);
+DEFINE_TYPE(SMPTE2094_40, std::optional<std::vector<uint8_t>>);
+
+#undef DEFINE_TYPE
+
+template <typename F, std::size_t... I>
+void invokeWithStandardMetadata(F&& f, StandardMetadataType type, std::index_sequence<I...>) {
+ // Setup the jump table, mapping from each type to a springboard that invokes the template
+ // function with the appropriate concrete type
+ using F_PTR = decltype(&f);
+ using THUNK = void (*)(F_PTR);
+ static constexpr auto jump = std::array<THUNK, sizeof...(I)>{[](F_PTR fp) {
+ constexpr StandardMetadataType type = ndk::internal::enum_values<StandardMetadataType>[I];
+ if constexpr (type != StandardMetadataType::INVALID) {
+ (*fp)(StandardMetadata<type>{});
+ }
+ }...};
+
+ auto index = static_cast<size_t>(type);
+ if (index >= 0 && index < jump.size()) {
+ jump[index](&f);
+ }
+}
+
+template <typename F, typename StandardMetadataSequence = std::make_index_sequence<
+ ndk::internal::enum_values<StandardMetadataType>.size()>>
+int32_t provideStandardMetadata(StandardMetadataType type, void* _Nullable destBuffer,
+ size_t destBufferSize, F&& f) {
+ int32_t retVal = -AIMAPPER_ERROR_UNSUPPORTED;
+ invokeWithStandardMetadata(
+ [&]<StandardMetadataType T>(StandardMetadata<T>) {
+ retVal = f.template operator()<T>(
+ [&](const typename StandardMetadata<T>::value_type& value) -> int32_t {
+ return StandardMetadata<T>::value::encode(value, destBuffer,
+ destBufferSize);
+ });
+ },
+ type, StandardMetadataSequence{});
+ return retVal;
+}
+
+template <typename F, typename StandardMetadataSequence = std::make_index_sequence<
+ ndk::internal::enum_values<StandardMetadataType>.size()>>
+AIMapper_Error applyStandardMetadata(StandardMetadataType type, const void* _Nonnull metadata,
+ size_t metadataSize, F&& f) {
+ AIMapper_Error retVal = AIMAPPER_ERROR_UNSUPPORTED;
+ invokeWithStandardMetadata(
+ [&]<StandardMetadataType T>(StandardMetadata<T>) {
+ auto value = StandardMetadata<T>::value::decode(metadata, metadataSize);
+ if (value.has_value()) {
+ retVal = f.template operator()<T>(std::move(*value));
+ } else {
+ retVal = AIMAPPER_ERROR_BAD_VALUE;
+ }
+ },
+ type, StandardMetadataSequence{});
+ return retVal;
+}
+
+} // namespace android::hardware::graphics::mapper
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h
new file mode 100644
index 0000000..957fdc9
--- /dev/null
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperProvider.h
@@ -0,0 +1,222 @@
+/*
+ * 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-base/unique_fd.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+#include <log/log.h>
+
+#include <mutex>
+#include <optional>
+#include <type_traits>
+
+/**
+ * Helper utilities for providing an IMapper-StableC implementation.
+ */
+
+namespace vendor::mapper {
+
+/**
+ * Extend from this interface to provide Version 5 of the IMapper interface
+ */
+struct IMapperV5Impl {
+ static const auto version = AIMAPPER_VERSION_5;
+ virtual ~IMapperV5Impl() = default;
+
+ virtual AIMapper_Error importBuffer(const native_handle_t* _Nonnull handle,
+ buffer_handle_t _Nullable* _Nonnull outBufferHandle) = 0;
+
+ virtual AIMapper_Error freeBuffer(buffer_handle_t _Nonnull buffer) = 0;
+
+ virtual AIMapper_Error getTransportSize(buffer_handle_t _Nonnull buffer,
+ uint32_t* _Nonnull outNumFds,
+ uint32_t* _Nonnull outNumInts) = 0;
+
+ virtual AIMapper_Error lock(buffer_handle_t _Nonnull buffer, uint64_t cpuUsage,
+ ARect accessRegion, int acquireFence,
+ void* _Nullable* _Nonnull outData) = 0;
+
+ virtual AIMapper_Error unlock(buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence) = 0;
+
+ virtual AIMapper_Error flushLockedBuffer(buffer_handle_t _Nonnull buffer) = 0;
+
+ virtual AIMapper_Error rereadLockedBuffer(buffer_handle_t _Nonnull buffer) = 0;
+
+ virtual int32_t getMetadata(buffer_handle_t _Nonnull buffer, AIMapper_MetadataType metadataType,
+ void* _Nullable destBuffer, size_t destBufferSize) = 0;
+
+ virtual int32_t getStandardMetadata(buffer_handle_t _Nonnull buffer,
+ int64_t standardMetadataType, void* _Nullable destBuffer,
+ size_t destBufferSize) = 0;
+
+ virtual AIMapper_Error setMetadata(buffer_handle_t _Nonnull buffer,
+ AIMapper_MetadataType metadataType,
+ const void* _Nonnull metadata, size_t metadataSize) = 0;
+
+ virtual AIMapper_Error setStandardMetadata(buffer_handle_t _Nonnull buffer,
+ int64_t standardMetadataType,
+ const void* _Nonnull metadata,
+ size_t metadataSize) = 0;
+
+ virtual AIMapper_Error listSupportedMetadataTypes(
+ const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+ size_t* _Nonnull outNumberOfDescriptions) = 0;
+
+ virtual AIMapper_Error dumpBuffer(buffer_handle_t _Nonnull bufferHandle,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context) = 0;
+
+ virtual AIMapper_Error dumpAllBuffers(
+ AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context) = 0;
+
+ virtual AIMapper_Error getReservedRegion(buffer_handle_t _Nonnull buffer,
+ void* _Nullable* _Nonnull outReservedRegion,
+ uint64_t* _Nonnull outReservedSize) = 0;
+};
+
+namespace provider {
+#ifndef __cpp_inline_variables
+#error "Only C++17 & newer is supported; inline variables is missing"
+#endif
+
+inline void* _Nullable sIMapperInstance = nullptr;
+} // namespace provider
+
+template <typename IMPL>
+class IMapperProvider {
+ private:
+ static_assert(IMPL::version >= AIMAPPER_VERSION_5, "Must be at least AIMAPPER_VERSION_5");
+ static_assert(std::is_final_v<IMPL>, "Implementation must be final");
+ static_assert(std::is_constructible_v<IMPL>, "Implementation must have a no-args constructor");
+
+ std::once_flag mLoadOnceFlag;
+ std::optional<IMPL> mImpl;
+ AIMapper mMapper = {};
+
+ static IMPL& impl() {
+ return *reinterpret_cast<IMapperProvider<IMPL>*>(provider::sIMapperInstance)->mImpl;
+ }
+
+ void bindV5() {
+ mMapper.v5 = {
+ .importBuffer = [](const native_handle_t* _Nonnull handle,
+ buffer_handle_t _Nullable* _Nonnull outBufferHandle)
+ -> AIMapper_Error { return impl().importBuffer(handle, outBufferHandle); },
+
+ .freeBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
+ return impl().freeBuffer(buffer);
+ },
+
+ .getTransportSize = [](buffer_handle_t _Nonnull buffer,
+ uint32_t* _Nonnull outNumFds,
+ uint32_t* _Nonnull outNumInts) -> AIMapper_Error {
+ return impl().getTransportSize(buffer, outNumFds, outNumInts);
+ },
+
+ .lock = [](buffer_handle_t _Nonnull buffer, uint64_t cpuUsage, ARect accessRegion,
+ int acquireFence, void* _Nullable* _Nonnull outData) -> AIMapper_Error {
+ return impl().lock(buffer, cpuUsage, accessRegion, acquireFence, outData);
+ },
+
+ .unlock = [](buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence)
+ -> AIMapper_Error { return impl().unlock(buffer, releaseFence); },
+
+ .flushLockedBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
+ return impl().flushLockedBuffer(buffer);
+ },
+
+ .rereadLockedBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
+ return impl().rereadLockedBuffer(buffer);
+ },
+
+ .getMetadata = [](buffer_handle_t _Nonnull buffer,
+ AIMapper_MetadataType metadataType, void* _Nullable destBuffer,
+ size_t destBufferSize) -> int32_t {
+ return impl().getMetadata(buffer, metadataType, destBuffer, destBufferSize);
+ },
+
+ .getStandardMetadata = [](buffer_handle_t _Nonnull buffer,
+ int64_t standardMetadataType, void* _Nullable destBuffer,
+ size_t destBufferSize) -> int32_t {
+ return impl().getStandardMetadata(buffer, standardMetadataType, destBuffer,
+ destBufferSize);
+ },
+
+ .setMetadata = [](buffer_handle_t _Nonnull buffer,
+ AIMapper_MetadataType metadataType, const void* _Nonnull metadata,
+ size_t metadataSize) -> AIMapper_Error {
+ return impl().setMetadata(buffer, metadataType, metadata, metadataSize);
+ },
+
+ .setStandardMetadata =
+ [](buffer_handle_t _Nonnull buffer, int64_t standardMetadataType,
+ const void* _Nonnull metadata, size_t metadataSize) -> AIMapper_Error {
+ return impl().setStandardMetadata(buffer, standardMetadataType, metadata,
+ metadataSize);
+ },
+
+ .listSupportedMetadataTypes =
+ [](const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+ size_t* _Nonnull outNumberOfDescriptions) -> AIMapper_Error {
+ return impl().listSupportedMetadataTypes(outDescriptionList,
+ outNumberOfDescriptions);
+ },
+
+ .dumpBuffer = [](buffer_handle_t _Nonnull bufferHandle,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context) -> AIMapper_Error {
+ return impl().dumpBuffer(bufferHandle, dumpBufferCallback, context);
+ },
+
+ .dumpAllBuffers =
+ [](AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context) {
+ return impl().dumpAllBuffers(beginDumpBufferCallback,
+ dumpBufferCallback, context);
+ },
+
+ .getReservedRegion = [](buffer_handle_t _Nonnull buffer,
+ void* _Nullable* _Nonnull outReservedRegion,
+ uint64_t* _Nonnull outReservedSize) -> AIMapper_Error {
+ return impl().getReservedRegion(buffer, outReservedRegion, outReservedSize);
+ },
+ };
+ }
+
+ public:
+ explicit IMapperProvider() = default;
+
+ AIMapper_Error load(AIMapper* _Nullable* _Nonnull outImplementation) {
+ std::call_once(mLoadOnceFlag, [this] {
+ LOG_ALWAYS_FATAL_IF(provider::sIMapperInstance != nullptr,
+ "AIMapper implementation already loaded!");
+ provider::sIMapperInstance = this;
+ mImpl.emplace();
+ mMapper.version = IMPL::version;
+ if (IMPL::version >= AIMAPPER_VERSION_5) {
+ bindV5();
+ }
+ });
+ *outImplementation = &mMapper;
+ return AIMAPPER_ERROR_NONE;
+ }
+};
+
+} // namespace vendor::mapper
diff --git a/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h b/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
new file mode 100644
index 0000000..f27b0f4
--- /dev/null
+++ b/graphics/mapper/stable-c/include/android/hardware/graphics/mapper/IMapper.h
@@ -0,0 +1,689 @@
+/*
+ * 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.
+ */
+
+/**
+ * IMapper Stable-C HAL interface
+ *
+ * This file represents the sphal interface between libui & the IMapper HAL implementation.
+ * A vendor implementation of this interface is retrieved by looking up the vendor imapper
+ * implementation library via the IAllocator AIDL interface.
+ *
+ * This interface is not intended for general use.
+ */
+
+#pragma once
+
+#include <sys/cdefs.h>
+#include <cinttypes>
+#include <cstddef>
+#include <type_traits>
+
+#include <android/rect.h>
+#include <cutils/native_handle.h>
+
+__BEGIN_DECLS
+
+/**
+ * AIMapper versioning
+ *
+ * IMapper versions 0-1 are pre-treble
+ * IMapper versions 2-4 are HIDL
+ * C-style AIMapper API starts at 5
+ */
+enum AIMapper_Version : uint32_t {
+ AIMAPPER_VERSION_5 = 5,
+};
+
+/**
+ * Possible AIMapper errors
+ * Values are the same as IMapper 4.0's Error type for simplicity
+ */
+enum AIMapper_Error : int32_t {
+ /**
+ * No error.
+ */
+ AIMAPPER_ERROR_NONE = 0,
+ /**
+ * Invalid BufferDescriptor.
+ */
+ AIMAPPER_ERROR_BAD_DESCRIPTOR = 1,
+ /**
+ * Invalid buffer handle.
+ */
+ AIMAPPER_ERROR_BAD_BUFFER = 2,
+ /**
+ * Invalid HardwareBufferDescription.
+ */
+ AIMAPPER_ERROR_BAD_VALUE = 3,
+ /**
+ * Resource unavailable.
+ */
+ AIMAPPER_ERROR_NO_RESOURCES = 5,
+ /**
+ * Permanent failure.
+ */
+ AIMAPPER_ERROR_UNSUPPORTED = 7,
+};
+
+/**
+ * MetadataType represents the different types of buffer metadata that could be
+ * associated with a buffer. It is used by IMapper to help get and set buffer metadata
+ * on the buffer's native handle.
+ *
+ * Standard buffer metadata will have the name field set to
+ * "android.hardware.graphics.common.StandardMetadataType" and will contain values
+ * from StandardMetadataType.aidl.
+ *
+ * Vendor-provided metadata should be prefixed with a "vendor.mycompanyname.*" namespace. It is
+ * recommended that the metadata follows the pattern of StandardMetadaType.aidl. That is, an
+ * aidl-defined enum with @VendorStability on it and the naming then matching that type such
+ * as "vendor.mycompanyname.graphics.common.MetadataType" with the value field then set to the
+ * aidl's enum value.
+ *
+ * Each company should create their own enum & namespace. The name
+ * field prevents values from different companies from colliding.
+ */
+typedef struct AIMapper_MetadataType {
+ const char* _Nonnull name;
+ int64_t value;
+} AIMapper_MetadataType;
+
+typedef struct AIMapper_MetadataTypeDescription {
+ /**
+ * The `name` of the metadataType must be valid for the lifetime of the process
+ */
+ AIMapper_MetadataType metadataType;
+ /**
+ * description should contain a string representation of the MetadataType.
+ *
+ * For example: "MyExampleMetadataType is a 64-bit timestamp in nanoseconds
+ * that indicates when a buffer is decoded. It is set by the media HAL after
+ * a buffer is decoded. It is used by the display HAL for hardware
+ * synchronization".
+ *
+ * This field is required for any non-StandardMetadataTypes. For StandardMetadataTypes this
+ * field may be null. The lifetime of this pointer must be valid for the duration of the
+ * process (that is, a static const char*).
+ */
+ const char* _Nullable description;
+ /**
+ * isGettable represents if the MetadataType can be get.
+ */
+ bool isGettable;
+ /**
+ * isSettable represents if the MetadataType can be set.
+ */
+ bool isSettable;
+
+ /** Reserved for future use; must be zero-initialized currently */
+ uint8_t reserved[32];
+} AIMapper_MetadataTypeDescription;
+
+/**
+ * Callback that is passed to dumpBuffer.
+ *
+ * @param context The caller-provided void* that was passed to dumpBuffer.
+ * @param metadataType The type of the metadata passed to the callback
+ * @param value A pointer to the value of the metadata. The lifetime of this pointer is only
+ * valid for the duration of the call
+ * @param valueSize The size of the value buffer.
+ */
+typedef void (*AIMapper_DumpBufferCallback)(void* _Null_unspecified context,
+ AIMapper_MetadataType metadataType,
+ const void* _Nonnull value, size_t valueSize);
+
+/**
+ * Callback that is passed to dumpAllBuffers.
+ *
+ * Indicates that a buffer is about to be dumped. Will be followed by N calls to
+ * AIMapper_DumpBufferCallback for all the metadata for this buffer.
+ *
+ * @param context The caller-provided void* that was passed to dumpAllBuffers.
+ */
+typedef void (*AIMapper_BeginDumpBufferCallback)(void* _Null_unspecified context);
+
+/**
+ * Implementation of AIMAPPER_VERSION_5
+ * All functions must not be null & must provide a valid implementation.
+ */
+typedef struct AIMapperV5 {
+ /**
+ * Imports a raw buffer handle to create an imported buffer handle for use
+ * with the rest of the mapper or with other in-process libraries.
+ *
+ * A buffer handle is considered raw when it is cloned (e.g., with
+ * `native_handle_clone()`) from another buffer handle locally, or when it
+ * is received from another HAL server/client or another process. A raw
+ * buffer handle must not be used to access the underlying graphic
+ * buffer. It must be imported to create an imported handle first.
+ *
+ * This function must at least validate the raw handle before creating the
+ * imported handle. It must also support importing the same raw handle
+ * multiple times to create multiple imported handles. The imported handle
+ * must be considered valid everywhere in the process, including in
+ * another instance of the mapper.
+ *
+ * Because of passthrough HALs, a raw buffer handle received from a HAL
+ * may actually have been imported in the process. importBuffer() must treat
+ * such a handle as if it is raw and must not return `BAD_BUFFER`. The
+ * returned handle is independent from the input handle as usual, and
+ * freeBuffer() must be called on it when it is no longer needed.
+ *
+ * @param handle Raw buffer handle to import.
+ * @param outBufferHandle The resulting imported buffer handle.
+ * @return Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `NO_RESOURCES` if the raw handle cannot be imported due to
+ * unavailability of resources.
+ */
+ AIMapper_Error (*_Nonnull importBuffer)(const native_handle_t* _Nonnull handle,
+ buffer_handle_t _Nullable* _Nonnull outBufferHandle);
+
+ /**
+ * Frees a buffer handle. Buffer handles returned by importBuffer() must be
+ * freed with this function when no longer needed.
+ *
+ * This function must free up all resources allocated by importBuffer() for
+ * the imported handle. For example, if the imported handle was created
+ * with `native_handle_create()`, this function must call
+ * `native_handle_close()` and `native_handle_delete()`.
+ *
+ * @param buffer Imported buffer handle.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ */
+ AIMapper_Error (*_Nonnull freeBuffer)(buffer_handle_t _Nonnull buffer);
+
+ /**
+ * Calculates the transport size of a buffer. An imported buffer handle is a
+ * raw buffer handle with the process-local runtime data appended. This
+ * function, for example, allows a caller to omit the process-local runtime
+ * data at the tail when serializing the imported buffer handle.
+ *
+ * Note that a client might or might not omit the process-local runtime data
+ * when sending an imported buffer handle. The mapper must support both
+ * cases on the receiving end.
+ *
+ * @param buffer Buffer to get the transport size from.
+ * @param outNumFds The number of file descriptors needed for transport.
+ * @param outNumInts The number of integers needed for transport.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ */
+ AIMapper_Error (*_Nonnull getTransportSize)(buffer_handle_t _Nonnull buffer,
+ uint32_t* _Nonnull outNumFds,
+ uint32_t* _Nonnull outNumInts);
+
+ /**
+ * Locks the given buffer for the specified CPU usage.
+ *
+ * Locking the same buffer simultaneously from multiple threads is
+ * permitted, but if any of the threads attempt to lock the buffer for
+ * writing, the behavior is undefined, except that it must not cause
+ * process termination or block the client indefinitely. Leaving the
+ * buffer content in an indeterminate state or returning an error are both
+ * acceptable.
+ *
+ * 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must
+ * "lock in place". The buffers must be directly accessible via mapping.
+ *
+ * The client must not modify the content of the buffer outside of
+ * @p accessRegion, and the device need not guarantee that content outside
+ * of @p accessRegion is valid for reading. The result of reading or writing
+ * outside of @p accessRegion is undefined, except that it must not cause
+ * process termination.
+ *
+ * An accessRegion of all-zeros means the entire buffer. That is, it is
+ * equivalent to '(0,0)-(buffer width, buffer height)'.
+ *
+ * This function can lock both single-planar and multi-planar formats. The caller
+ * should use get() to get information about the buffer they are locking.
+ * get() can be used to get information about the planes, offsets, stride,
+ * etc.
+ *
+ * This function must also work on buffers with
+ * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well
+ * as with any other formats requested by multimedia codecs when they are
+ * configured with a flexible-YUV-compatible color format.
+ *
+ * On success, @p data must be filled with a pointer to the locked buffer
+ * memory. This address will represent the top-left corner of the entire
+ * buffer, even if @p accessRegion does not begin at the top-left corner.
+ *
+ * The locked buffer must adhere to the format requested at allocation time
+ * in the BufferDescriptorInfo.
+ *
+ * @param buffer Buffer to lock.
+ * @param cpuUsage CPU usage flags to request. See BufferUsage.aidl for possible values.
+ * @param accessRegion Portion of the buffer that the client intends to
+ * access.
+ * @param acquireFence Handle containing a file descriptor referring to a
+ * sync fence object, which will be signaled when it is safe for the
+ * mapper to lock the buffer. @p acquireFence may be an empty fence (-1) if
+ * it is already safe to lock. Ownership is passed to the callee and it is the
+ * implementations responsibility to ensure it is closed even when an error
+ * occurs.
+ * @param outData CPU-accessible pointer to the buffer data.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this
+ * function.
+ * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or
+ * is incompatible with the buffer. Also if the @p accessRegion is
+ * outside the bounds of the buffer or the accessRegion is invalid.
+ * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
+ * that locking may succeed at a later time.
+ * @return data CPU-accessible pointer to the buffer data.
+ */
+ AIMapper_Error (*_Nonnull lock)(buffer_handle_t _Nonnull buffer, uint64_t cpuUsage,
+ ARect accessRegion, int acquireFence,
+ void* _Nullable* _Nonnull outData);
+
+ /**
+ * Unlocks a buffer to indicate all CPU accesses to the buffer have
+ * completed.
+ *
+ * @param buffer Buffer to unlock.
+ * @param releaseFence Handle containing a file descriptor referring to a
+ * sync fence object. The sync fence object will be signaled when the
+ * mapper has completed any pending work. @p releaseFence may be an
+ * empty fence (-1).
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ */
+ AIMapper_Error (*_Nonnull unlock)(buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence);
+
+ /**
+ * Flushes the contents of a locked buffer.
+ *
+ * This function flushes the CPUs caches for the range of all the buffer's
+ * planes and metadata. This should behave similarly to unlock() except the
+ * buffer should remain mapped to the CPU.
+ *
+ * The client is still responsible for calling unlock() when it is done
+ * with all CPU accesses to the buffer.
+ *
+ * If non-CPU blocks are simultaneously writing the buffer, the locked
+ * copy should still be flushed but what happens is undefined except that
+ * it should not cause any crashes.
+ *
+ * @param buffer Buffer to flush.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ */
+ AIMapper_Error (*_Nonnull flushLockedBuffer)(buffer_handle_t _Nonnull buffer);
+
+ /**
+ * Rereads the contents of a locked buffer.
+ *
+ * This should fetch the most recent copy of the locked buffer.
+ *
+ * It may reread locked copies of the buffer in other processes.
+ *
+ * The client is still responsible for calling unlock() when it is done
+ * with all CPU accesses to the buffer.
+ *
+ * @param buffer Buffer to reread.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ * - `NO_RESOURCES` if the buffer cannot be reread at this time. Note
+ * that rereading may succeed at a later time.
+ */
+ AIMapper_Error (*_Nonnull rereadLockedBuffer)(buffer_handle_t _Nonnull buffer);
+
+ /**
+ * Description for get(...), set(...) and getFromBufferDescriptorInfo(...)
+ *
+ * ------------ Overview -----------------------------------
+ * Gralloc 4 adds support for getting and setting buffer metadata on a buffer.
+ *
+ * To get buffer metadata, the client passes in a buffer handle and a token that
+ * represents the type of buffer metadata they would like to get. IMapper returns
+ * a byte stream that contains the buffer metadata. To set the buffer metadata, the
+ * client passes in a buffer handle and a token that represents the type of buffer
+ * metadata they would like to set and a byte stream that contains the buffer metadata
+ * they are setting.
+ *
+ * Buffer metadata is global for a buffer. When the metadata is set on the buffer
+ * in a process, the updated metadata should be available to all other processes.
+ * Please see "Storing and Propagating Metadata" below for more details.
+ *
+ * The getter and setter functions have been optimized for easy vendor extension.
+ * They do not require a formal extension to add support for getting and setting
+ * vendor defined buffer metadata. See "Buffer Metadata Token" and
+ * "Buffer Metadata Stream" below for more details.
+ *
+ * ------------ Storing and Propagating Metadata -----------
+ * Buffer metadata must be global. Any changes to the metadata must be propagated
+ * to all other processes immediately. Vendors may chose how they would like support
+ * this functionality.
+ *
+ * We recommend supporting this functionality by allocating an extra page of shared
+ * memory and storing it in the buffer's native_handle_t. The buffer metadata can
+ * be stored in the extra page of shared memory. Set operations are automatically
+ * propagated to all other processes.
+ *
+ * ------------ Buffer Metadata Synchronization ------------
+ * There are no explicit buffer metadata synchronization primitives. Many devices
+ * before gralloc 4 already support getting and setting of global buffer metadata
+ * with no explicit synchronization primitives. Adding synchronization primitives
+ * would just add unnecessary complexity.
+ *
+ * The general rule is if a process has permission to write to a buffer, they
+ * have permission to write to the buffer's writable metadata. If a process has permission
+ * to read from a buffer, they have permission to read the buffer's metadata.
+ *
+ * There is one exception to this rule. Fences CANNOT be used to protect a buffer's
+ * metadata. A process should finish writing to a buffer's metadata before
+ * sending the buffer to another process that will read or write to the buffer.
+ * This exception is needed because sometimes userspace needs to read the
+ * buffer's metadata before the buffer's contents are ready.
+ *
+ * As a simple example: an app renders to a buffer and then displays the buffer.
+ * In this example when the app renders to the buffer, both the buffer and its
+ * metadata need to be updated. The app's process queues up its work on the GPU
+ * and gets back an acquire fence. The app's process must update the buffer's
+ * metadata before enqueuing the buffer to SurfaceFlinger. The app process CANNOT
+ * update the buffer's metadata after enqueuing the buffer. When HardwareComposer
+ * receives the buffer, it is immediately safe to read the buffer's metadata
+ * and use it to program the display driver. To read the buffer's contents,
+ * display driver must still wait on the acquire fence.
+ *
+ * ------------ Buffer Metadata Token ----------------------
+ * In order to allow arbitrary vendor defined metadata, the token used to access
+ * metadata is defined defined as a struct that has a string representing
+ * the enum type and an int that represents the enum value. The string protects
+ * different enum values from colliding.
+ *
+ * The token struct (MetadataType) is defined as a C struct since it
+ * is passed into a C function. The standard buffer metadata types are NOT
+ * defined as a C enum but instead as an AIDL enum to allow for broader usage across
+ * other HALs and libraries. By putting the enum in the
+ * stable AIDL (hardware/interfaces/graphics/common/aidl/android/hardware/
+ * graphics/common/StandardMetadataType.aidl), vendors will be able to optionally
+ * choose to support future standard buffer metadata types without upgrading
+ * IMapper versions. For more information see the description of "struct MetadataType".
+ *
+ * ------------ Buffer Metadata Stream ---------------------
+ * The buffer metadata is get and set as a void* buffer. By getting
+ * and setting buffer metadata as a generic buffer, vendors can use the standard
+ * getters and setter functions defined here. Vendors do NOT need to add their own
+ * getters and setter functions for each new type of buffer metadata.
+ *
+ * Converting buffer metadata into a byte stream can be non-trivial. For the standard
+ * buffer metadata types defined in StandardMetadataType.aidl, there are also
+ * support functions that will encode the buffer metadata into a byte stream
+ * and decode the buffer metadata from a byte stream. We STRONGLY recommend using
+ * these support functions. The framework will use them when getting and setting
+ * metadata. The support functions are defined in
+ * frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
+ */
+
+ /**
+ * Gets the buffer metadata for a given MetadataType.
+ *
+ * Buffer metadata can be changed after allocation so clients should avoid "caching"
+ * the buffer metadata. For example, if the video resolution changes and the buffers
+ * are not reallocated, several buffer metadata values may change without warning.
+ * Clients should not expect the values to be constant. They should requery them every
+ * frame. The only exception is buffer metadata that is determined at allocation
+ * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
+ * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
+ * they are determined at allocation time.
+ *
+ * @param buffer Buffer containing desired metadata
+ * @param metadataType MetadataType for the metadata value being queried
+ * @param destBuffer Pointer to a buffer in which to store the result of the get() call; if
+ * null, the computed output size or error must still be returned.
+ * @param destBufferSize How large the destBuffer buffer is. If destBuffer is null this must be
+ * 0.
+ * @return The number of bytes written to `destBuffer` or which would have been written
+ * if `destBufferSize` was large enough.
+ * A negative value indicates an error, which may be
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `UNSUPPORTED` when metadataType is unknown/unsupported.
+ * IMapper must support getting all StandardMetadataType.aidl values defined
+ * at the time the device first launches.
+ */
+ int32_t (*_Nonnull getMetadata)(buffer_handle_t _Nonnull buffer,
+ AIMapper_MetadataType metadataType, void* _Nullable destBuffer,
+ size_t destBufferSize);
+
+ /**
+ * Gets the buffer metadata for a StandardMetadataType.
+ *
+ * This is equivalent to `getMetadata` when passed an AIMapper_MetadataType with name
+ * set to "android.hardware.graphics.common.StandardMetadataType"
+ *
+ * Buffer metadata can be changed after allocation so clients should avoid "caching"
+ * the buffer metadata. For example, if the video resolution changes and the buffers
+ * are not reallocated, several buffer metadata values may change without warning.
+ * Clients should not expect the values to be constant. They should requery them every
+ * frame. The only exception is buffer metadata that is determined at allocation
+ * time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
+ * HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
+ * they are determined at allocation time.
+ *
+ * @param buffer Buffer containing desired metadata
+ * @param standardMetadataType StandardMetadataType for the metadata value being queried
+ * @param destBuffer Pointer to a buffer in which to store the result of the get() call; if
+ * null, the computed output size or error must still be returned.
+ * @param destBufferSize How large the destBuffer buffer is. If destBuffer is null this must be
+ * 0.
+ * @return The number of bytes written to `destBuffer` or which would have been written
+ * if `destBufferSize` was large enough.
+ * A negative value indicates an error, which may be
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `UNSUPPORTED` when metadataType is unknown/unsupported.
+ * IMapper must support getting all StandardMetadataType.aidl values defined
+ * at the time the device first launches.
+ */
+ int32_t (*_Nonnull getStandardMetadata)(buffer_handle_t _Nonnull buffer,
+ int64_t standardMetadataType,
+ void* _Nullable destBuffer, size_t destBufferSize);
+
+ /**
+ * Sets the global value for a given MetadataType.
+ *
+ * Metadata fields are not required to be settable. This function can
+ * return Error::UNSUPPORTED whenever it doesn't support setting a
+ * particular Metadata field.
+ *
+ * The framework will attempt to set the following StandardMetadataType
+ * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
+ * We require everyone to support setting those fields. If a device's Composer
+ * implementation supports a field, it should be supported here. Over time these
+ * metadata fields will be moved out of Composer/BufferQueue/etc. and into the
+ * buffer's Metadata fields.
+ *
+ * @param buffer Buffer receiving desired metadata
+ * @param metadataType MetadataType for the metadata value being set
+ * @param metadata Pointer to a buffer of bytes representing the value associated with
+ * @param metadataSize The size of the metadata buffer
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `BAD_VALUE` when the field is constant and can never be set (such as
+ * BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
+ * USAGE)
+ * - `NO_RESOURCES` if the set cannot be fulfilled due to unavailability of
+ * resources.
+ * - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
+ * it is unsupported. Unsupported should also be returned if the metadata
+ * is malformed.
+ */
+ AIMapper_Error (*_Nonnull setMetadata)(buffer_handle_t _Nonnull buffer,
+ AIMapper_MetadataType metadataType,
+ const void* _Nonnull metadata, size_t metadataSize);
+
+ /**
+ * Sets the global value for a given MetadataType.
+ *
+ * This is equivalent to `setMetadata` when passed an AIMapper_MetadataType with name
+ * set to "android.hardware.graphics.common.StandardMetadataType"
+ *
+ * Metadata fields are not required to be settable. This function can
+ * return Error::UNSUPPORTED whenever it doesn't support setting a
+ * particular Metadata field.
+ *
+ * The framework will attempt to set the following StandardMetadataType
+ * values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
+ * We require everyone to support setting those fields. If a device's Composer
+ * implementation supports a field, it should be supported here. Over time these
+ * metadata fields will be moved out of Composer/BufferQueue/etc. and into the
+ * buffer's Metadata fields.
+ *
+ * @param buffer Buffer receiving desired metadata
+ * @param standardMetadataType StandardMetadataType for the metadata value being set
+ * @param metadata Pointer to a buffer of bytes representing the value associated with
+ * @param metadataSize The size of the metadata buffer
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `BAD_VALUE` when the field is constant and can never be set (such as
+ * BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
+ * USAGE)
+ * - `NO_RESOURCES` if the set cannot be fulfilled due to unavailability of
+ * resources.
+ * - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
+ * it is unsupported. Unsupported should also be returned if the metadata
+ * is malformed.
+ */
+ AIMapper_Error (*_Nonnull setStandardMetadata)(buffer_handle_t _Nonnull buffer,
+ int64_t standardMetadataType,
+ const void* _Nonnull metadata,
+ size_t metadataSize);
+
+ /**
+ * Lists all the MetadataTypes supported by IMapper as well as a description
+ * of each supported MetadataType. For StandardMetadataTypes, the description
+ * string can be left empty.
+ *
+ * This list is expected to be static & thus the returned array must be valid for the
+ * lifetime of the process.
+ *
+ * @param outDescriptionList The list of descriptions
+ * @param outNumberOfDescriptions How many descriptions are in `outDescriptionList`
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `UNSUPPORTED` if there's any error
+ */
+ AIMapper_Error (*_Nonnull listSupportedMetadataTypes)(
+ const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
+ size_t* _Nonnull outNumberOfDescriptions);
+
+ /**
+ * Dumps a buffer's metadata.
+ *
+ * @param buffer The buffer to dump the metadata for
+ * @param dumpBufferCallback Callback that will be invoked for each of the metadata fields
+ * @param context A caller-provided context to be passed to the dumpBufferCallback
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `NO_RESOURCES` if the get cannot be fulfilled due to unavailability of
+ * resources.
+ */
+ AIMapper_Error (*_Nonnull dumpBuffer)(buffer_handle_t _Nonnull buffer,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context);
+
+ /**
+ * Dump the metadata for all imported buffers in the current process
+ *
+ * The HAL implementation should invoke beginDumpCallback before dumping a buffer's metadata,
+ * followed by N calls to dumpBufferCallback for that buffer's metadata fields. The call
+ * sequence should follow this pseudocode:
+ *
+ * for (auto buffer : gListOfImportedBuffers) {
+ * beginDumpCallback(context);
+ * for (auto metadata : buffer->allMetadata()) {
+ * dumpBufferCallback(context, metadata...);
+ * }
+ * }
+ *
+ * @param beginDumpCallback Signals that a buffer is about to be dumped
+ * @param dumpBufferCallback Callback that will be invoked for each of the metadata fields
+ * @param context A caller-provided context to be passed to beginDumpCallback and
+ * dumpBufferCallback
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `NO_RESOURCES` if the get cannot be fulfilled due to unavailability of
+ * resources.
+ */
+ AIMapper_Error (*_Nonnull dumpAllBuffers)(
+ AIMapper_BeginDumpBufferCallback _Nonnull beginDumpCallback,
+ AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
+ void* _Null_unspecified context);
+
+ /**
+ * Returns the region of shared memory associated with the buffer that is
+ * reserved for client use.
+ *
+ * The shared memory may be allocated from any shared memory allocator.
+ * The shared memory must be CPU-accessible and virtually contiguous. The
+ * starting address must be word-aligned.
+ *
+ * This function may only be called after importBuffer() has been called by the
+ * client. The reserved region must remain accessible until freeBuffer() has
+ * been called. After freeBuffer() has been called, the client must not access
+ * the reserved region.
+ *
+ * This reserved memory may be used in future versions of Android to
+ * help clients implement backwards compatible features without requiring
+ * IAllocator/IMapper updates.
+ *
+ * @param buffer Imported buffer handle.
+ * @param outReservedRegion CPU-accessible pointer to the reserved region
+ * @param outReservedSize the size of the reservedRegion that was requested
+ * in the BufferDescriptorInfo.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ */
+ AIMapper_Error (*_Nonnull getReservedRegion)(buffer_handle_t _Nonnull buffer,
+ void* _Nullable* _Nonnull outReservedRegion,
+ uint64_t* _Nonnull outReservedSize);
+
+} AIMapperV5;
+
+/**
+ * Return value for AIMapper_loadIMapper
+ *
+ * Note: This struct's size is not fixed and callers must never store it by-value as a result.
+ * Only fields up to those covered by `version` are allowed to be accessed.
+ */
+typedef struct AIMapper {
+ alignas(alignof(max_align_t)) AIMapper_Version version;
+ AIMapperV5 v5;
+} AIMapper;
+
+/**
+ * Loads the vendor-provided implementation of AIMapper
+ * @return Error status of the call.
+ * - `NONE` upon success
+ * - `UNSUPPORTED` if no implementation is available
+ */
+AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation);
+
+__END_DECLS
\ No newline at end of file
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
new file mode 100644
index 0000000..6ab11a3
--- /dev/null
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -0,0 +1,1565 @@
+/*
+ * Copyright 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "VtsHalGraphicsMapperStableC_TargetTest"
+
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationError.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationResult.h>
+#include <aidl/android/hardware/graphics/allocator/IAllocator.h>
+#include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_manager.h>
+#include <android/dlext.h>
+#include <android/hardware/graphics/mapper/IMapper.h>
+#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
+#include <gralloctypes/Gralloc4.h>
+#include <hidl/GtestPrinter.h>
+#include <system/graphics.h>
+
+#include <dlfcn.h>
+#include <drm/drm_fourcc.h>
+#include <gtest/gtest.h>
+#include <vndksupport/linker.h>
+#include <initializer_list>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <vector>
+
+using namespace aidl::android::hardware::graphics::allocator;
+using namespace aidl::android::hardware::graphics::common;
+using namespace android;
+using namespace android::hardware;
+using namespace ::android::hardware::graphics::mapper;
+
+typedef AIMapper_Error (*AIMapper_loadIMapperFn)(AIMapper* _Nullable* _Nonnull outImplementation);
+
+inline constexpr BufferUsage operator|(BufferUsage lhs, BufferUsage rhs) {
+ using T = std::underlying_type_t<BufferUsage>;
+ return static_cast<BufferUsage>(static_cast<T>(lhs) | static_cast<T>(rhs));
+}
+
+inline BufferUsage& operator|=(BufferUsage& lhs, BufferUsage rhs) {
+ lhs = lhs | rhs;
+ return lhs;
+}
+
+struct YCbCr {
+ android_ycbcr yCbCr;
+ int64_t horizontalSubSampling;
+ int64_t verticalSubSampling;
+};
+
+class BufferHandle {
+ AIMapper* mIMapper;
+ buffer_handle_t mHandle = nullptr;
+
+ public:
+ explicit BufferHandle(AIMapper* mapper, native_handle_t* rawHandle) : mIMapper(mapper) {
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mIMapper->v5.importBuffer(rawHandle, &mHandle));
+ }
+
+ explicit BufferHandle(BufferHandle&& other) { *this = std::move(other); }
+
+ BufferHandle& operator=(BufferHandle&& other) noexcept {
+ reset();
+ mIMapper = other.mIMapper;
+ mHandle = other.mHandle;
+ other.mHandle = nullptr;
+ return *this;
+ }
+
+ ~BufferHandle() { reset(); }
+
+ constexpr explicit operator bool() const noexcept { return mHandle != nullptr; }
+
+ buffer_handle_t operator*() const noexcept { return mHandle; }
+
+ void reset() {
+ if (mHandle != nullptr) {
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mIMapper->v5.freeBuffer(mHandle));
+ mHandle = nullptr;
+ }
+ }
+};
+
+class BufferAllocation {
+ AIMapper* mIMapper;
+ native_handle_t* mRawHandle;
+ uint32_t mStride;
+ const BufferDescriptorInfo mInfo;
+
+ public:
+ BufferAllocation(const BufferAllocation&) = delete;
+ void operator=(const BufferAllocation&) = delete;
+
+ BufferAllocation(AIMapper* mapper, native_handle_t* handle, uint32_t stride,
+ const BufferDescriptorInfo& info)
+ : mIMapper(mapper), mRawHandle(handle), mStride(stride), mInfo(info) {}
+
+ ~BufferAllocation() {
+ if (mRawHandle == nullptr) return;
+
+ native_handle_close(mRawHandle);
+ native_handle_delete(mRawHandle);
+ }
+
+ uint32_t stride() const { return mStride; }
+ const BufferDescriptorInfo& info() const { return mInfo; }
+
+ BufferHandle import() { return BufferHandle{mIMapper, mRawHandle}; }
+
+ const native_handle_t* rawHandle() const { return mRawHandle; }
+};
+
+class GraphicsTestsBase {
+ private:
+ friend class BufferAllocation;
+ int32_t mIAllocatorVersion = 1;
+ std::shared_ptr<IAllocator> mAllocator;
+ AIMapper* mIMapper = nullptr;
+ AIMapper_loadIMapperFn mIMapperLoader;
+
+ protected:
+ void Initialize(std::shared_ptr<IAllocator> allocator) {
+ mAllocator = allocator;
+ ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+ ASSERT_TRUE(mAllocator->getInterfaceVersion(&mIAllocatorVersion).isOk());
+ ASSERT_GE(mIAllocatorVersion, 2);
+ std::string mapperSuffix;
+ auto status = mAllocator->getIMapperLibrarySuffix(&mapperSuffix);
+ ASSERT_TRUE(status.isOk()) << "Failed to get IMapper library suffix";
+ std::string lib_name = "mapper." + mapperSuffix + ".so";
+ void* so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW);
+ ASSERT_NE(nullptr, so) << "Failed to load " << lib_name;
+ mIMapperLoader = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
+ ASSERT_NE(nullptr, mIMapperLoader) << "AIMapper_locaIMapper missing from " << lib_name;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mIMapperLoader(&mIMapper));
+ ASSERT_NE(mIMapper, nullptr);
+ }
+
+ public:
+ AIMapper_loadIMapperFn getIMapperLoader() const { return mIMapperLoader; }
+
+ std::unique_ptr<BufferAllocation> allocate(const BufferDescriptorInfo& descriptorInfo) {
+ AllocationResult result;
+ ::ndk::ScopedAStatus status = mAllocator->allocate2(descriptorInfo, 1, &result);
+ if (!status.isOk()) {
+ status_t error = status.getExceptionCode();
+ if (error == EX_SERVICE_SPECIFIC) {
+ error = status.getServiceSpecificError();
+ EXPECT_NE(OK, error) << "Failed to set error properly";
+ } else {
+ EXPECT_EQ(OK, error) << "Allocation transport failure";
+ }
+ return nullptr;
+ } else {
+ return std::make_unique<BufferAllocation>(mIMapper, dupFromAidl(result.buffers[0]),
+ result.stride, descriptorInfo);
+ }
+ }
+
+ std::unique_ptr<BufferAllocation> allocateGeneric() {
+ return allocate({
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ }
+
+ bool isSupported(const BufferDescriptorInfo& descriptorInfo) {
+ bool ret = false;
+ EXPECT_TRUE(mAllocator->isSupported(descriptorInfo, &ret).isOk());
+ return ret;
+ }
+
+ AIMapper* mapper() const { return mIMapper; }
+
+ template <StandardMetadataType T>
+ auto getStandardMetadata(buffer_handle_t bufferHandle)
+ -> decltype(StandardMetadata<T>::value::decode(nullptr, 0)) {
+ using Value = typename StandardMetadata<T>::value;
+ std::vector<uint8_t> buffer;
+ // Initial guess
+ buffer.resize(512);
+ int32_t sizeRequired = mapper()->v5.getStandardMetadata(
+ bufferHandle, static_cast<int64_t>(T), buffer.data(), buffer.size());
+ if (sizeRequired < 0) {
+ EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, sizeRequired)
+ << "Received something other than UNSUPPORTED from valid getStandardMetadata "
+ "call";
+ return std::nullopt;
+ }
+ if (sizeRequired > buffer.size()) {
+ buffer.resize(sizeRequired);
+ sizeRequired = mapper()->v5.getStandardMetadata(bufferHandle, static_cast<int64_t>(T),
+ buffer.data(), buffer.size());
+ }
+ if (sizeRequired < 0 || sizeRequired >= buffer.size()) {
+ ADD_FAILURE() << "getStandardMetadata failed, received " << sizeRequired
+ << " with buffer size " << buffer.size();
+ // Generate a fail type
+ return std::nullopt;
+ }
+ return Value::decode(buffer.data(), sizeRequired);
+ }
+
+ template <StandardMetadataType T>
+ AIMapper_Error setStandardMetadata(buffer_handle_t bufferHandle,
+ const typename StandardMetadata<T>::value_type& value) {
+ using Value = typename StandardMetadata<T>::value;
+ int32_t sizeRequired = Value::encode(value, nullptr, 0);
+ if (sizeRequired < 0) {
+ EXPECT_GE(sizeRequired, 0) << "Failed to calculate required size";
+ return static_cast<AIMapper_Error>(-sizeRequired);
+ }
+ std::vector<uint8_t> buffer;
+ buffer.resize(sizeRequired);
+ sizeRequired = Value::encode(value, buffer.data(), buffer.size());
+ if (sizeRequired < 0 || sizeRequired > buffer.size()) {
+ ADD_FAILURE() << "Failed to encode with calculated size " << sizeRequired
+ << "; buffer size" << buffer.size();
+ return static_cast<AIMapper_Error>(-sizeRequired);
+ }
+ return mapper()->v5.setStandardMetadata(bufferHandle, static_cast<int64_t>(T),
+ buffer.data(), sizeRequired);
+ }
+
+ void verifyRGBA8888PlaneLayouts(const std::vector<PlaneLayout>& planeLayouts) {
+ ASSERT_EQ(1, planeLayouts.size());
+
+ const auto& planeLayout = planeLayouts.front();
+
+ ASSERT_EQ(4, planeLayout.components.size());
+
+ int64_t offsetInBitsR = -1;
+ int64_t offsetInBitsG = -1;
+ int64_t offsetInBitsB = -1;
+ int64_t offsetInBitsA = -1;
+
+ for (const auto& component : planeLayout.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(component.type)) {
+ continue;
+ }
+ EXPECT_EQ(8, component.sizeInBits);
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_R.value) {
+ offsetInBitsR = component.offsetInBits;
+ }
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_G.value) {
+ offsetInBitsG = component.offsetInBits;
+ }
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_B.value) {
+ offsetInBitsB = component.offsetInBits;
+ }
+ if (component.type.value == gralloc4::PlaneLayoutComponentType_A.value) {
+ offsetInBitsA = component.offsetInBits;
+ }
+ }
+
+ EXPECT_EQ(0, offsetInBitsR);
+ EXPECT_EQ(8, offsetInBitsG);
+ EXPECT_EQ(16, offsetInBitsB);
+ EXPECT_EQ(24, offsetInBitsA);
+
+ EXPECT_EQ(0, planeLayout.offsetInBytes);
+ EXPECT_EQ(32, planeLayout.sampleIncrementInBits);
+ // Skip testing stride because any stride is valid
+ EXPECT_LE(planeLayout.widthInSamples * planeLayout.heightInSamples * 4,
+ planeLayout.totalSizeInBytes);
+ EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+ EXPECT_EQ(1, planeLayout.verticalSubsampling);
+ }
+
+ void fillRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes) {
+ for (uint32_t y = 0; y < height; y++) {
+ memset(data, y, widthInBytes);
+ data += strideInBytes;
+ }
+ }
+
+ void verifyRGBA8888(const buffer_handle_t bufferHandle, const uint8_t* data, uint32_t height,
+ size_t strideInBytes, size_t widthInBytes) {
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(bufferHandle);
+ ASSERT_TRUE(decodeResult.has_value());
+ const auto& planeLayouts = *decodeResult;
+ ASSERT_TRUE(planeLayouts.size() > 0);
+
+ verifyRGBA8888PlaneLayouts(planeLayouts);
+
+ for (uint32_t y = 0; y < height; y++) {
+ for (size_t i = 0; i < widthInBytes; i++) {
+ EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
+ }
+ data += strideInBytes;
+ }
+ }
+
+ void traverseYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+ int64_t hSubsampling, int64_t vSubsampling,
+ std::function<void(uint8_t*, uint8_t)> traverseFuncion) {
+ auto yData = static_cast<uint8_t*>(yCbCr.y);
+ auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+ auto crData = static_cast<uint8_t*>(yCbCr.cr);
+ auto yStride = yCbCr.ystride;
+ auto cStride = yCbCr.cstride;
+ auto chromaStep = yCbCr.chroma_step;
+
+ for (uint32_t y = 0; y < height; y++) {
+ for (uint32_t x = 0; x < width; x++) {
+ auto val = static_cast<uint8_t>(height * y + x);
+
+ traverseFuncion(yData + yStride * y + x, val);
+
+ if (y % vSubsampling == 0 && x % hSubsampling == 0) {
+ uint32_t subSampleX = x / hSubsampling;
+ uint32_t subSampleY = y / vSubsampling;
+ const auto subSampleOffset = cStride * subSampleY + chromaStep * subSampleX;
+ const auto subSampleVal =
+ static_cast<uint8_t>(height * subSampleY + subSampleX);
+
+ traverseFuncion(cbData + subSampleOffset, subSampleVal);
+ traverseFuncion(crData + subSampleOffset, subSampleVal + 1);
+ }
+ }
+ }
+ }
+
+ void fillYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+ int64_t hSubsampling, int64_t vSubsampling) {
+ traverseYCbCrData(yCbCr, width, height, hSubsampling, vSubsampling,
+ [](auto address, auto fillingData) { *address = fillingData; });
+ }
+
+ void verifyYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+ int64_t hSubsampling, int64_t vSubsampling) {
+ traverseYCbCrData(
+ yCbCr, width, height, hSubsampling, vSubsampling,
+ [](auto address, auto expectedData) { EXPECT_EQ(*address, expectedData); });
+ }
+
+ constexpr uint64_t bitsToBytes(int64_t bits) { return bits / 8; }
+ constexpr uint64_t bytesToBits(int64_t bytes) { return bytes * 8; }
+
+ void getAndroidYCbCr(buffer_handle_t bufferHandle, uint8_t* data, android_ycbcr* outYCbCr,
+ int64_t* hSubsampling, int64_t* vSubsampling) {
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(bufferHandle);
+ ASSERT_TRUE(decodeResult.has_value());
+ const auto& planeLayouts = *decodeResult;
+ ASSERT_TRUE(planeLayouts.size() > 0);
+
+ outYCbCr->y = nullptr;
+ outYCbCr->cb = nullptr;
+ outYCbCr->cr = nullptr;
+ outYCbCr->ystride = 0;
+ outYCbCr->cstride = 0;
+ outYCbCr->chroma_step = 0;
+
+ for (const auto& planeLayout : planeLayouts) {
+ for (const auto& planeLayoutComponent : planeLayout.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
+ continue;
+ }
+ ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+
+ uint8_t* tmpData = data + planeLayout.offsetInBytes +
+ bitsToBytes(planeLayoutComponent.offsetInBits);
+ uint64_t sampleIncrementInBytes;
+
+ auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
+ switch (type) {
+ case PlaneLayoutComponentType::Y:
+ ASSERT_EQ(nullptr, outYCbCr->y);
+ ASSERT_EQ(8, planeLayoutComponent.sizeInBits);
+ ASSERT_EQ(8, planeLayout.sampleIncrementInBits);
+ outYCbCr->y = tmpData;
+ outYCbCr->ystride = planeLayout.strideInBytes;
+ break;
+
+ case PlaneLayoutComponentType::CB:
+ case PlaneLayoutComponentType::CR:
+ ASSERT_EQ(0, planeLayout.sampleIncrementInBits % 8);
+
+ sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
+ ASSERT_TRUE(sampleIncrementInBytes == 1 || sampleIncrementInBytes == 2);
+
+ if (outYCbCr->cstride == 0 && outYCbCr->chroma_step == 0) {
+ outYCbCr->cstride = planeLayout.strideInBytes;
+ outYCbCr->chroma_step = sampleIncrementInBytes;
+ } else {
+ ASSERT_EQ(outYCbCr->cstride, planeLayout.strideInBytes);
+ ASSERT_EQ(outYCbCr->chroma_step, sampleIncrementInBytes);
+ }
+
+ if (*hSubsampling == 0 && *vSubsampling == 0) {
+ *hSubsampling = planeLayout.horizontalSubsampling;
+ *vSubsampling = planeLayout.verticalSubsampling;
+ } else {
+ ASSERT_EQ(*hSubsampling, planeLayout.horizontalSubsampling);
+ ASSERT_EQ(*vSubsampling, planeLayout.verticalSubsampling);
+ }
+
+ if (type == PlaneLayoutComponentType::CB) {
+ ASSERT_EQ(nullptr, outYCbCr->cb);
+ outYCbCr->cb = tmpData;
+ } else {
+ ASSERT_EQ(nullptr, outYCbCr->cr);
+ outYCbCr->cr = tmpData;
+ }
+ break;
+ default:
+ break;
+ };
+ }
+ }
+
+ ASSERT_NE(nullptr, outYCbCr->y);
+ ASSERT_NE(nullptr, outYCbCr->cb);
+ ASSERT_NE(nullptr, outYCbCr->cr);
+ }
+
+ YCbCr getAndroidYCbCr_P010(const native_handle_t* bufferHandle, uint8_t* data) {
+ YCbCr yCbCr_P010;
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(bufferHandle);
+ if (!decodeResult.has_value()) {
+ ADD_FAILURE() << "failed to get plane layout";
+ return YCbCr{};
+ }
+ const auto& planeLayouts = *decodeResult;
+ EXPECT_EQ(2, planeLayouts.size());
+ EXPECT_EQ(1, planeLayouts[0].components.size());
+ EXPECT_EQ(2, planeLayouts[1].components.size());
+
+ yCbCr_P010.yCbCr.y = nullptr;
+ yCbCr_P010.yCbCr.cb = nullptr;
+ yCbCr_P010.yCbCr.cr = nullptr;
+ yCbCr_P010.yCbCr.ystride = 0;
+ yCbCr_P010.yCbCr.cstride = 0;
+ yCbCr_P010.yCbCr.chroma_step = 0;
+ int64_t cb_offset = 0;
+ int64_t cr_offset = 0;
+
+ for (const auto& planeLayout : planeLayouts) {
+ for (const auto& planeLayoutComponent : planeLayout.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
+ continue;
+ }
+
+ uint8_t* tmpData = data + planeLayout.offsetInBytes +
+ bitsToBytes(planeLayoutComponent.offsetInBits);
+ uint64_t sampleIncrementInBytes = 0;
+ auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
+ switch (type) {
+ case PlaneLayoutComponentType::Y:
+ // For specs refer:
+ // https://docs.microsoft.com/en-us/windows/win32/medfound/10-bit-and-16-bit-yuv-video-formats
+ EXPECT_EQ(6, planeLayoutComponent.offsetInBits);
+ EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.y);
+ EXPECT_EQ(10, planeLayoutComponent.sizeInBits);
+ EXPECT_EQ(16, planeLayout.sampleIncrementInBits);
+
+ yCbCr_P010.yCbCr.y = tmpData;
+ yCbCr_P010.yCbCr.ystride = planeLayout.strideInBytes;
+ break;
+
+ case PlaneLayoutComponentType::CB:
+ case PlaneLayoutComponentType::CR:
+ sampleIncrementInBytes = bitsToBytes(planeLayout.sampleIncrementInBits);
+ EXPECT_EQ(4, sampleIncrementInBytes);
+
+ if (yCbCr_P010.yCbCr.cstride == 0 && yCbCr_P010.yCbCr.chroma_step == 0) {
+ yCbCr_P010.yCbCr.cstride = planeLayout.strideInBytes;
+ yCbCr_P010.yCbCr.chroma_step = sampleIncrementInBytes;
+ } else {
+ EXPECT_EQ(yCbCr_P010.yCbCr.cstride, planeLayout.strideInBytes);
+ EXPECT_EQ(yCbCr_P010.yCbCr.chroma_step, sampleIncrementInBytes);
+ }
+
+ if (yCbCr_P010.horizontalSubSampling == 0 &&
+ yCbCr_P010.verticalSubSampling == 0) {
+ yCbCr_P010.horizontalSubSampling = planeLayout.horizontalSubsampling;
+ yCbCr_P010.verticalSubSampling = planeLayout.verticalSubsampling;
+ } else {
+ EXPECT_EQ(yCbCr_P010.horizontalSubSampling,
+ planeLayout.horizontalSubsampling);
+ EXPECT_EQ(yCbCr_P010.verticalSubSampling,
+ planeLayout.verticalSubsampling);
+ }
+
+ if (type == PlaneLayoutComponentType::CB) {
+ EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cb);
+ yCbCr_P010.yCbCr.cb = tmpData;
+ cb_offset = planeLayoutComponent.offsetInBits;
+ } else {
+ EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cr);
+ yCbCr_P010.yCbCr.cr = tmpData;
+ cr_offset = planeLayoutComponent.offsetInBits;
+ }
+ break;
+ default:
+ break;
+ };
+ }
+ }
+
+ EXPECT_EQ(cb_offset + bytesToBits(2), cr_offset);
+ EXPECT_NE(nullptr, yCbCr_P010.yCbCr.y);
+ EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cb);
+ EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cr);
+ return yCbCr_P010;
+ }
+};
+
+class GraphicsMapperStableCTests
+ : public GraphicsTestsBase,
+ public ::testing::TestWithParam<std::tuple<std::string, std::shared_ptr<IAllocator>>> {
+ public:
+ void SetUp() override { Initialize(std::get<1>(GetParam())); }
+
+ void TearDown() override {}
+};
+
+TEST_P(GraphicsMapperStableCTests, AllV5CallbacksDefined) {
+ ASSERT_GE(mapper()->version, AIMAPPER_VERSION_5);
+
+ EXPECT_TRUE(mapper()->v5.importBuffer);
+ EXPECT_TRUE(mapper()->v5.freeBuffer);
+ EXPECT_TRUE(mapper()->v5.getTransportSize);
+ EXPECT_TRUE(mapper()->v5.lock);
+ EXPECT_TRUE(mapper()->v5.unlock);
+ EXPECT_TRUE(mapper()->v5.flushLockedBuffer);
+ EXPECT_TRUE(mapper()->v5.rereadLockedBuffer);
+ EXPECT_TRUE(mapper()->v5.getMetadata);
+ EXPECT_TRUE(mapper()->v5.getStandardMetadata);
+ EXPECT_TRUE(mapper()->v5.setMetadata);
+ EXPECT_TRUE(mapper()->v5.setStandardMetadata);
+ EXPECT_TRUE(mapper()->v5.listSupportedMetadataTypes);
+ EXPECT_TRUE(mapper()->v5.dumpBuffer);
+ EXPECT_TRUE(mapper()->v5.getReservedRegion);
+}
+
+TEST_P(GraphicsMapperStableCTests, DualLoadIsIdentical) {
+ ASSERT_GE(mapper()->version, AIMAPPER_VERSION_5);
+ AIMapper* secondMapper;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, getIMapperLoader()(&secondMapper));
+
+ EXPECT_EQ(secondMapper->v5.importBuffer, mapper()->v5.importBuffer);
+ EXPECT_EQ(secondMapper->v5.freeBuffer, mapper()->v5.freeBuffer);
+ EXPECT_EQ(secondMapper->v5.getTransportSize, mapper()->v5.getTransportSize);
+ EXPECT_EQ(secondMapper->v5.lock, mapper()->v5.lock);
+ EXPECT_EQ(secondMapper->v5.unlock, mapper()->v5.unlock);
+ EXPECT_EQ(secondMapper->v5.flushLockedBuffer, mapper()->v5.flushLockedBuffer);
+ EXPECT_EQ(secondMapper->v5.rereadLockedBuffer, mapper()->v5.rereadLockedBuffer);
+ EXPECT_EQ(secondMapper->v5.getMetadata, mapper()->v5.getMetadata);
+ EXPECT_EQ(secondMapper->v5.getStandardMetadata, mapper()->v5.getStandardMetadata);
+ EXPECT_EQ(secondMapper->v5.setMetadata, mapper()->v5.setMetadata);
+ EXPECT_EQ(secondMapper->v5.setStandardMetadata, mapper()->v5.setStandardMetadata);
+ EXPECT_EQ(secondMapper->v5.listSupportedMetadataTypes, mapper()->v5.listSupportedMetadataTypes);
+ EXPECT_EQ(secondMapper->v5.dumpBuffer, mapper()->v5.dumpBuffer);
+ EXPECT_EQ(secondMapper->v5.getReservedRegion, mapper()->v5.getReservedRegion);
+}
+
+TEST_P(GraphicsMapperStableCTests, CanAllocate) {
+ auto buffer = allocate({
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ ASSERT_NE(nullptr, buffer.get());
+ EXPECT_GE(buffer->stride(), 64);
+}
+
+TEST_P(GraphicsMapperStableCTests, ImportFreeBuffer) {
+ auto buffer = allocate({
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ ASSERT_NE(nullptr, buffer.get());
+ EXPECT_GE(buffer->stride(), 64);
+
+ {
+ auto import1 = buffer->import();
+ auto import2 = buffer->import();
+ EXPECT_TRUE(import1);
+ EXPECT_TRUE(import2);
+ EXPECT_NE(*import1, *import2);
+ }
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
+ */
+TEST_P(GraphicsMapperStableCTests, ImportFreeBufferSingleton) {
+ auto buffer = allocate({
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ ASSERT_NE(nullptr, buffer.get());
+ EXPECT_GE(buffer->stride(), 64);
+
+ buffer_handle_t bufferHandle = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.importBuffer(buffer->rawHandle(), &bufferHandle));
+ ASSERT_NE(nullptr, bufferHandle);
+
+ AIMapper* secondMapper;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, getIMapperLoader()(&secondMapper));
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, secondMapper->v5.freeBuffer(bufferHandle));
+}
+
+/**
+ * Test IMapper::importBuffer with invalid buffers.
+ */
+TEST_P(GraphicsMapperStableCTests, ImportBufferNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ buffer_handle_t bufferHandle = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.importBuffer(invalidHandle, &bufferHandle))
+ << "importBuffer with nullptr did not fail with BAD_BUFFER";
+
+ invalidHandle = native_handle_create(0, 0);
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.importBuffer(invalidHandle, &bufferHandle))
+ << "importBuffer with invalid handle did not fail with BAD_BUFFER";
+ native_handle_delete(invalidHandle);
+}
+
+/**
+ * Test IMapper::freeBuffer with invalid buffers.
+ */
+TEST_P(GraphicsMapperStableCTests, FreeBufferNegative) {
+ native_handle_t* bufferHandle = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.freeBuffer(bufferHandle))
+ << "freeBuffer with nullptr did not fail with BAD_BUFFER";
+
+ bufferHandle = native_handle_create(0, 0);
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.freeBuffer(bufferHandle))
+ << "freeBuffer with invalid handle did not fail with BAD_BUFFER";
+ native_handle_delete(bufferHandle);
+
+ auto buffer = allocateGeneric();
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.freeBuffer(buffer->rawHandle()))
+ << "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
+}
+
+/**
+ * Test IMapper::lock and IMapper::unlock.
+ */
+TEST_P(GraphicsMapperStableCTests, LockUnlockBasic) {
+ constexpr auto usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN;
+ auto buffer = allocate({
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = usage,
+ .reservedSize = 0,
+ });
+ ASSERT_NE(nullptr, buffer.get());
+
+ // lock buffer for writing
+ const auto& info = buffer->info();
+ const auto stride = buffer->stride();
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE,
+ mapper()->v5.lock(*handle, static_cast<int64_t>(usage), region, -1, (void**)&data));
+
+ // RGBA_8888
+ fillRGBA8888(data, info.height, stride * 4, info.width * 4);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+ // lock again for reading
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(usage), region,
+ releaseFence, (void**)&data));
+ releaseFence = -1;
+
+ ASSERT_NO_FATAL_FAILURE(verifyRGBA8888(*handle, data, info.height, stride * 4, info.width * 4));
+
+ releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+/**
+ * Test multiple operations associated with different color formats
+ */
+TEST_P(GraphicsMapperStableCTests, Lock_YCRCB_420_SP) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::YCRCB_420_SP,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ if (!buffer) {
+ ASSERT_FALSE(isSupported(info));
+ GTEST_SUCCEED() << "YCRCB_420_SP format is unsupported";
+ return;
+ }
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ android_ycbcr yCbCr;
+ int64_t hSubsampling = 0;
+ int64_t vSubsampling = 0;
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+ ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+ auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+ auto crData = static_cast<uint8_t*>(yCbCr.cr);
+ ASSERT_EQ(crData + 1, cbData);
+ ASSERT_EQ(2, yCbCr.chroma_step);
+
+ fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+ // lock again for reading
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, releaseFence, (void**)&data));
+ releaseFence = -1;
+
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, YV12SubsampleMetadata) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::YV12,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ ASSERT_NE(nullptr, buffer.get());
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*handle);
+ ASSERT_TRUE(decodeResult.has_value());
+ const auto& planeLayouts = *decodeResult;
+
+ ASSERT_EQ(3, planeLayouts.size());
+
+ auto yPlane = planeLayouts[0];
+ auto crPlane = planeLayouts[1];
+ auto cbPlane = planeLayouts[2];
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ EXPECT_EQ(kCbCrSubSampleFactor, crPlane.horizontalSubsampling);
+ EXPECT_EQ(kCbCrSubSampleFactor, crPlane.verticalSubsampling);
+
+ EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.horizontalSubsampling);
+ EXPECT_EQ(kCbCrSubSampleFactor, cbPlane.verticalSubsampling);
+
+ const long chromaSampleWidth = info.width / kCbCrSubSampleFactor;
+ const long chromaSampleHeight = info.height / kCbCrSubSampleFactor;
+
+ EXPECT_EQ(info.width, yPlane.widthInSamples);
+ EXPECT_EQ(info.height, yPlane.heightInSamples);
+
+ EXPECT_EQ(chromaSampleWidth, crPlane.widthInSamples);
+ EXPECT_EQ(chromaSampleHeight, crPlane.heightInSamples);
+
+ EXPECT_EQ(chromaSampleWidth, cbPlane.widthInSamples);
+ EXPECT_EQ(chromaSampleHeight, cbPlane.heightInSamples);
+
+ EXPECT_LE(crPlane.widthInSamples, crPlane.strideInBytes);
+ EXPECT_LE(cbPlane.widthInSamples, cbPlane.strideInBytes);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_YV12) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::YV12,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ ASSERT_NE(nullptr, buffer.get());
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ android_ycbcr yCbCr;
+ int64_t hSubsampling = 0;
+ int64_t vSubsampling = 0;
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+ ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+ auto cbData = static_cast<uint8_t*>(yCbCr.cb);
+ auto crData = static_cast<uint8_t*>(yCbCr.cr);
+ ASSERT_EQ(crData + yCbCr.cstride * info.height / vSubsampling, cbData);
+ ASSERT_EQ(1, yCbCr.chroma_step);
+
+ fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+ // lock again for reading
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, releaseFence, (void**)&data));
+ releaseFence = -1;
+
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_YCBCR_420_888) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::YCBCR_420_888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ ASSERT_NE(nullptr, buffer.get());
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ android_ycbcr yCbCr;
+ int64_t hSubsampling = 0;
+ int64_t vSubsampling = 0;
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
+ ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
+
+ fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+
+ // lock again for reading
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, releaseFence, (void**)&data));
+ releaseFence = -1;
+
+ ASSERT_NO_FATAL_FAILURE(getAndroidYCbCr(*handle, data, &yCbCr, &hSubsampling, &vSubsampling));
+
+ verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_RAW10) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RAW10,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ if (!buffer) {
+ ASSERT_FALSE(isSupported(info));
+ GTEST_SUCCEED() << "RAW10 format is unsupported";
+ return;
+ }
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*handle);
+ ASSERT_TRUE(decodeResult.has_value());
+ const auto& planeLayouts = *decodeResult;
+
+ ASSERT_EQ(1, planeLayouts.size());
+ auto planeLayout = planeLayouts[0];
+
+ EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
+ EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+ EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+ ASSERT_EQ(1, planeLayout.components.size());
+ auto planeLayoutComponent = planeLayout.components[0];
+
+ EXPECT_EQ(PlaneLayoutComponentType::RAW,
+ static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
+ EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+ EXPECT_EQ(-1, planeLayoutComponent.sizeInBits);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_RAW12) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RAW12,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ if (!buffer) {
+ ASSERT_FALSE(isSupported(info));
+ GTEST_SUCCEED() << "RAW12 format is unsupported";
+ return;
+ }
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ auto decodeResult = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*handle);
+ ASSERT_TRUE(decodeResult.has_value());
+ const auto& planeLayouts = *decodeResult;
+
+ ASSERT_EQ(1, planeLayouts.size());
+ auto planeLayout = planeLayouts[0];
+
+ EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
+ EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+ EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+ ASSERT_EQ(1, planeLayout.components.size());
+ auto planeLayoutComponent = planeLayout.components[0];
+
+ EXPECT_EQ(PlaneLayoutComponentType::RAW,
+ static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
+ EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+ EXPECT_EQ(-1, planeLayoutComponent.sizeInBits);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, Lock_YCBCR_P010) {
+ BufferDescriptorInfo info{
+ .name = {"VTS_TEMP"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::YCBCR_P010,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ if (!buffer) {
+ ASSERT_FALSE(isSupported(info));
+ GTEST_SUCCEED() << "YCBCR_P010 format is unsupported";
+ return;
+ }
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width, info.height};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+
+ YCbCr yCbCr;
+ ASSERT_NO_FATAL_FAILURE(yCbCr = getAndroidYCbCr_P010(*handle, data));
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.horizontalSubSampling);
+ ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.verticalSubSampling);
+
+ ASSERT_EQ(0, info.height % 2);
+
+ // fill the data
+ fillYCbCrData(yCbCr.yCbCr, info.width, info.height, yCbCr.horizontalSubSampling,
+ yCbCr.verticalSubSampling);
+ // verify the YCbCr data
+ verifyYCbCrData(yCbCr.yCbCr, info.width, info.height, yCbCr.horizontalSubSampling,
+ yCbCr.verticalSubSampling);
+
+ int releaseFence = -1;
+ ASSERT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, LockBadAccessRegion) {
+ auto buffer = allocateGeneric();
+ ASSERT_NE(nullptr, buffer);
+ const auto& info = buffer->info();
+
+ // lock buffer for writing
+ const ARect region{0, 0, info.width * 2, info.height * 2};
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_VALUE, mapper()->v5.lock(*handle, static_cast<int64_t>(info.usage),
+ region, -1, (void**)&data));
+}
+
+TEST_P(GraphicsMapperStableCTests, UnlockNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ int releaseFence = -1;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(invalidHandle, &releaseFence))
+ << "unlock with nullptr did not fail with BAD_BUFFER";
+
+ invalidHandle = native_handle_create(0, 0);
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(invalidHandle, &releaseFence))
+ << "unlock with invalid handle did not fail with BAD_BUFFER";
+ native_handle_delete(invalidHandle);
+
+ auto buffer = allocateGeneric();
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(buffer->rawHandle(), &releaseFence))
+ << "unlock with un-imported handle did not fail with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, UnlockNotImported) {
+ int releaseFence = -1;
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(buffer->rawHandle(), &releaseFence))
+ << "unlock with un-imported handle did not fail with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, UnlockNotLocked) {
+ int releaseFence = -1;
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(*bufferHandle, &releaseFence))
+ << "unlock with unlocked handle did not fail with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, LockUnlockNested) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ const ARect region{0, 0, buffer->info().width, buffer->info().height};
+ auto usage = static_cast<int64_t>(buffer->info().usage);
+ auto handle = buffer->import();
+ uint8_t* data = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, usage, region, -1, (void**)&data));
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.lock(*handle, usage, region, -1, (void**)&data))
+ << "Second lock failed";
+ int releaseFence = -1;
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ releaseFence = -1;
+ }
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*handle, &releaseFence))
+ << "Second unlock failed";
+ if (releaseFence != -1) {
+ close(releaseFence);
+ releaseFence = -1;
+ }
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.unlock(*handle, &releaseFence))
+ << "Third, unmatched, unlock should have failed with BAD_BUFFER";
+}
+
+TEST_P(GraphicsMapperStableCTests, FlushRereadBasic) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ const auto& info = buffer->info();
+ const auto stride = buffer->stride();
+ const ARect region{0, 0, buffer->info().width, buffer->info().height};
+
+ auto writeHandle = buffer->import();
+ auto readHandle = buffer->import();
+ ASSERT_TRUE(writeHandle && readHandle);
+
+ // lock buffer for writing
+
+ uint8_t* writeData;
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ mapper()->v5.lock(*writeHandle, static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN),
+ region, -1, (void**)&writeData));
+
+ uint8_t* readData;
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ mapper()->v5.lock(*readHandle, static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN),
+ region, -1, (void**)&readData));
+
+ fillRGBA8888(writeData, info.height, stride * 4, info.width * 4);
+
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.flushLockedBuffer(*writeHandle));
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.rereadLockedBuffer(*readHandle));
+
+ ASSERT_NO_FATAL_FAILURE(
+ verifyRGBA8888(*readHandle, readData, info.height, stride * 4, info.width * 4));
+
+ int releaseFence = -1;
+
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*readHandle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ releaseFence = -1;
+ }
+
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, mapper()->v5.unlock(*writeHandle, &releaseFence));
+ if (releaseFence != -1) {
+ close(releaseFence);
+ releaseFence = -1;
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, FlushLockedBufferBadBuffer) {
+ // Amazingly this is enough to make the compiler happy even though flushLockedBuffer
+ // is _Nonnull :shrug:
+ buffer_handle_t badBuffer = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.flushLockedBuffer(badBuffer));
+}
+
+TEST_P(GraphicsMapperStableCTests, RereadLockedBufferBadBuffer) {
+ buffer_handle_t badBuffer = nullptr;
+ EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, mapper()->v5.rereadLockedBuffer(badBuffer));
+}
+
+TEST_P(GraphicsMapperStableCTests, GetBufferId) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto bufferId = getStandardMetadata<StandardMetadataType::BUFFER_ID>(*bufferHandle);
+ ASSERT_TRUE(bufferId.has_value());
+
+ auto buffer2 = allocateGeneric();
+ auto bufferHandle2 = buffer2->import();
+ auto bufferId2 = getStandardMetadata<StandardMetadataType::BUFFER_ID>(*bufferHandle2);
+ ASSERT_TRUE(bufferId2.has_value());
+
+ EXPECT_NE(*bufferId, *bufferId2);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetName) {
+ auto buffer = allocate({
+ .name = {"Hello, World!"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ auto bufferHandle = buffer->import();
+ auto name = getStandardMetadata<StandardMetadataType::NAME>(*bufferHandle);
+ ASSERT_TRUE(name.has_value());
+ EXPECT_EQ(*name, "Hello, World!");
+}
+
+TEST_P(GraphicsMapperStableCTests, GetWidthHeight) {
+ auto buffer = allocate({
+ .name = {"Hello, World!"},
+ .width = 64,
+ .height = 128,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::WIDTH>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, 64);
+ value = getStandardMetadata<StandardMetadataType::HEIGHT>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, 128);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetLayerCount) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::LAYER_COUNT>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, buffer->info().layerCount);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPixelFormatRequested) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_REQUESTED>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, buffer->info().format);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPixelFormatFourCC) {
+ auto buffer = allocate({
+ .name = {"Hello, World!"},
+ .width = 64,
+ .height = 128,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ {
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_FOURCC>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, DRM_FORMAT_ABGR8888);
+ }
+
+ buffer = allocate({
+ .name = {"yv12"},
+ .width = 64,
+ .height = 128,
+ .layerCount = 1,
+ .format = PixelFormat::YV12,
+ .usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
+ .reservedSize = 0,
+ });
+ {
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_FOURCC>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, DRM_FORMAT_YVU420);
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPixelFormatModifier) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::PIXEL_FORMAT_MODIFIER>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ // Only the upper 8-bits are defined and is just the vendor ID, the lower 56 bits are
+ // then vendor specific. So there's not anything useful to assert here beyond just that
+ // we successfully queried a value
+}
+
+TEST_P(GraphicsMapperStableCTests, GetUsage) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::USAGE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(buffer->info().usage, *value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetAllocationSize) {
+ auto buffer = allocateGeneric();
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::ALLOCATION_SIZE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ const auto estimatedSize = buffer->stride() * buffer->info().height * 4;
+ // This buffer has CPU usage, so we expect at least stride * height * 4 since it should be
+ // generally linear uncompressed.
+ EXPECT_GE(*value, estimatedSize)
+ << "Expected allocation size to be at least stride * height * 4bpp";
+ // Might need refining, but hopefully this a generous-enough upper-bound?
+ EXPECT_LT(*value, estimatedSize * 2)
+ << "Expected allocation size to less than double stride * height * 4bpp";
+}
+
+TEST_P(GraphicsMapperStableCTests, GetProtectedContent) {
+ const BufferDescriptorInfo info{
+ .name = {"prot8888"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::PROTECTED | BufferUsage::COMPOSER_OVERLAY,
+ .reservedSize = 0,
+ };
+ auto buffer = allocate(info);
+ if (!buffer) {
+ ASSERT_FALSE(isSupported(info))
+ << "Allocation of trivial sized buffer failed, so isSupported() must be false";
+ GTEST_SUCCEED() << "PROTECTED RGBA_8888 is unsupported";
+ return;
+ }
+ auto bufferHandle = buffer->import();
+ auto value = getStandardMetadata<StandardMetadataType::PROTECTED_CONTENT>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(*value, 1);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetCompression) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::COMPRESSION>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(gralloc4::Compression_None.name, value->name);
+ EXPECT_EQ(gralloc4::Compression_None.value, value->value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetInterlaced) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::INTERLACED>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(gralloc4::Interlaced_None.name, value->name);
+ EXPECT_EQ(gralloc4::Interlaced_None.value, value->value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetChromaSiting) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::CHROMA_SITING>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(gralloc4::ChromaSiting_None.name, value->name);
+ EXPECT_EQ(gralloc4::ChromaSiting_None.value, value->value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetPlaneLayouts) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::PLANE_LAYOUTS>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_NO_FATAL_FAILURE(verifyRGBA8888PlaneLayouts(*value));
+}
+
+TEST_P(GraphicsMapperStableCTests, GetCrop) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::CROP>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(1, value->size());
+ const Rect expected{0, 0, buffer->info().width, buffer->info().height};
+ EXPECT_EQ(expected, value->at(0));
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSetDataspace) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::DATASPACE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Dataspace::UNKNOWN, *value);
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, setStandardMetadata<StandardMetadataType::DATASPACE>(
+ *bufferHandle, Dataspace::DISPLAY_P3));
+ value = getStandardMetadata<StandardMetadataType::DATASPACE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Dataspace::DISPLAY_P3, *value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSetBlendMode) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::BLEND_MODE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(BlendMode::INVALID, *value);
+ EXPECT_EQ(AIMAPPER_ERROR_NONE, setStandardMetadata<StandardMetadataType::BLEND_MODE>(
+ *bufferHandle, BlendMode::COVERAGE));
+ value = getStandardMetadata<StandardMetadataType::BLEND_MODE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(BlendMode::COVERAGE, *value);
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSetSmpte2086) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_FALSE(value->has_value());
+
+ // TODO: Maybe use something resembling real values, but validation isn't supposed to happen
+ // here anyway so :shrug:
+ const Smpte2086 awesomeHdr{
+ XyColor{1.f, 1.f}, XyColor{2.f, 2.f}, XyColor{3.f, 3.f},
+ XyColor{400.f, 1000.f}, 100000.0f, 0.0001f,
+ };
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ setStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle, awesomeHdr));
+ value = getStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_TRUE(value->has_value());
+ EXPECT_EQ(awesomeHdr, *value);
+
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ setStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle, std::nullopt));
+ value = getStandardMetadata<StandardMetadataType::SMPTE2086>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_FALSE(value->has_value());
+}
+
+TEST_P(GraphicsMapperStableCTests, GetCta861_3) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_FALSE(value->has_value());
+
+ const Cta861_3 genericHlgish{1000.f, 140.f};
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ setStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle, genericHlgish));
+ value = getStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_TRUE(value->has_value());
+ EXPECT_EQ(genericHlgish, *value);
+
+ EXPECT_EQ(AIMAPPER_ERROR_NONE,
+ setStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle, std::nullopt));
+ value = getStandardMetadata<StandardMetadataType::CTA861_3>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_FALSE(value->has_value());
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSmpte2094_10) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::SMPTE2094_10>(*bufferHandle);
+ if (value.has_value()) {
+ EXPECT_FALSE(value->has_value());
+ }
+}
+
+TEST_P(GraphicsMapperStableCTests, GetSmpte2094_40) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::SMPTE2094_40>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_FALSE(value->has_value());
+}
+
+std::vector<std::tuple<std::string, std::shared_ptr<IAllocator>>> getIAllocatorsAtLeastVersion(
+ int32_t minVersion) {
+ auto instanceNames = getAidlHalInstanceNames(IAllocator::descriptor);
+ std::vector<std::tuple<std::string, std::shared_ptr<IAllocator>>> filteredInstances;
+ filteredInstances.reserve(instanceNames.size());
+ for (const auto& name : instanceNames) {
+ auto allocator =
+ IAllocator::fromBinder(ndk::SpAIBinder(AServiceManager_checkService(name.c_str())));
+ int32_t version = 0;
+ if (allocator->getInterfaceVersion(&version).isOk()) {
+ if (version >= minVersion) {
+ filteredInstances.emplace_back(name, std::move(allocator));
+ }
+ }
+ }
+ return filteredInstances;
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperStableCTests);
+INSTANTIATE_TEST_CASE_P(PerInstance, GraphicsMapperStableCTests,
+ testing::ValuesIn(getIAllocatorsAtLeastVersion(2)),
+ [](auto info) -> std::string {
+ std::string name =
+ std::to_string(info.index) + "/" + std::get<0>(info.param);
+ return Sanitize(name);
+ });
\ No newline at end of file
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index f568f7a..2090473 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -15,10 +15,10 @@
],
imports: [
"android.hardware.keymaster-V3",
- "android.hardware.security.keymint-V3",
+ "android.hardware.security.rkp-V3",
],
stability: "vintf",
- frozen: false,
+ frozen: true,
backend: {
java: {
platform_apis: true,
@@ -32,28 +32,28 @@
version: "1",
imports: [
"android.hardware.keymaster-V3",
- "android.hardware.security.keymint-V1",
+ "android.hardware.security.rkp-V1",
],
},
{
version: "2",
imports: [
"android.hardware.keymaster-V3",
- "android.hardware.security.keymint-V1",
+ "android.hardware.security.rkp-V1",
],
},
{
version: "3",
imports: [
"android.hardware.keymaster-V3",
- "android.hardware.security.keymint-V1",
+ "android.hardware.security.rkp-V1",
],
},
{
version: "4",
imports: [
"android.hardware.keymaster-V3",
- "android.hardware.security.keymint-V2",
+ "android.hardware.security.rkp-V3",
],
},
@@ -67,20 +67,20 @@
cc_defaults {
name: "identity_use_latest_hal_aidl_ndk_static",
static_libs: [
- "android.hardware.identity-V5-ndk",
+ "android.hardware.identity-V4-ndk",
],
}
cc_defaults {
name: "identity_use_latest_hal_aidl_ndk_shared",
shared_libs: [
- "android.hardware.identity-V5-ndk",
+ "android.hardware.identity-V4-ndk",
],
}
cc_defaults {
name: "identity_use_latest_hal_aidl_cpp_static",
static_libs: [
- "android.hardware.identity-V5-cpp",
+ "android.hardware.identity-V4-cpp",
],
}
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index a57875a..7bc3c8d 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -45,6 +45,7 @@
"libpuresoftkeymasterdevice",
"android.hardware.identity-support-lib",
"android.hardware.keymaster-V3-ndk",
+ "android.hardware.security.rkp-V3-ndk",
],
}
@@ -112,6 +113,7 @@
"android.hardware.keymaster-V3-ndk",
"android.hardware.identity-libeic-hal-common",
"android.hardware.identity-libeic-library",
+ "android.hardware.security.rkp-V3-ndk",
],
srcs: [
"service.cpp",
diff --git a/identity/aidl/default/EicOpsImpl.cc b/identity/aidl/default/EicOpsImpl.cc
index b6d324f..803df64 100644
--- a/identity/aidl/default/EicOpsImpl.cc
+++ b/identity/aidl/default/EicOpsImpl.cc
@@ -489,7 +489,7 @@
}
bool eicOpsEcdh(const uint8_t publicKey[EIC_P256_PUB_KEY_SIZE],
- const uint8_t privateKey[EIC_P256_PUB_KEY_SIZE],
+ const uint8_t privateKey[EIC_P256_PRIV_KEY_SIZE],
uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE]) {
vector<uint8_t> pubKeyVec(EIC_P256_PUB_KEY_SIZE + 1);
pubKeyVec[0] = 0x04;
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 54bf887..5e303bb 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -39,6 +39,8 @@
"libcrypto",
],
static_libs: [
+ "android.hardware.security.rkp-V3-cpp",
+ "android.hardware.security.rkp-V3-ndk",
"android.hardware.security.secureclock-V1-ndk",
"libcppbor_external",
"libcppcose_rkp",
diff --git a/media/bufferpool/aidl/Android.bp b/media/bufferpool/aidl/Android.bp
index 3b2ea3c..68ac489 100644
--- a/media/bufferpool/aidl/Android.bp
+++ b/media/bufferpool/aidl/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+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.bufferpool2",
vendor_available: true,
diff --git a/oemlock/aidl/default/OemLock.cpp b/oemlock/aidl/default/OemLock.cpp
index 646b532..234a8a9 100644
--- a/oemlock/aidl/default/OemLock.cpp
+++ b/oemlock/aidl/default/OemLock.cpp
@@ -24,29 +24,31 @@
// Methods from ::android::hardware::oemlock::IOemLock follow.
::ndk::ScopedAStatus OemLock::getName(std::string *out_name) {
- (void)out_name;
+ *out_name = "SomeCoolName";
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus OemLock::setOemUnlockAllowedByCarrier(bool in_allowed, const std::vector<uint8_t> &in_signature, OemLockSecureStatus *_aidl_return) {
- (void)in_allowed;
+ // Default impl doesn't care about a valid vendor signature
(void)in_signature;
- (void)_aidl_return;
+
+ mAllowedByCarrier = in_allowed;
+ *_aidl_return = OemLockSecureStatus::OK;
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus OemLock::isOemUnlockAllowedByCarrier(bool *out_allowed) {
- (void)out_allowed;
+ *out_allowed = mAllowedByCarrier;
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus OemLock::setOemUnlockAllowedByDevice(bool in_allowed) {
- (void)in_allowed;
+ mAllowedByDevice = in_allowed;
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus OemLock::isOemUnlockAllowedByDevice(bool *out_allowed) {
- (void)out_allowed;
+ *out_allowed = mAllowedByDevice;
return ::ndk::ScopedAStatus::ok();
}
diff --git a/oemlock/aidl/default/OemLock.h b/oemlock/aidl/default/OemLock.h
index b0df414..9dff21a 100644
--- a/oemlock/aidl/default/OemLock.h
+++ b/oemlock/aidl/default/OemLock.h
@@ -36,6 +36,10 @@
::ndk::ScopedAStatus isOemUnlockAllowedByDevice(bool* out_allowed) override;
::ndk::ScopedAStatus setOemUnlockAllowedByCarrier(bool in_allowed, const std::vector<uint8_t>& in_signature, OemLockSecureStatus* _aidl_return) override;
::ndk::ScopedAStatus setOemUnlockAllowedByDevice(bool in_allowed) override;
+
+ private:
+ bool mAllowedByCarrier = false;
+ bool mAllowedByDevice = false;
};
} // namespace oemlock
diff --git a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
index 928668c..e6809da 100644
--- a/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
+++ b/power/aidl/aidl_api/android.hardware.power/current/android/hardware/power/IPowerHintSession.aidl
@@ -40,4 +40,5 @@
oneway void resume();
oneway void close();
oneway void sendHint(android.hardware.power.SessionHint hint);
+ void setThreads(in int[] threadIds);
}
diff --git a/power/aidl/android/hardware/power/IPowerHintSession.aidl b/power/aidl/android/hardware/power/IPowerHintSession.aidl
index 4ca9c54..7db0ea1 100644
--- a/power/aidl/android/hardware/power/IPowerHintSession.aidl
+++ b/power/aidl/android/hardware/power/IPowerHintSession.aidl
@@ -20,7 +20,7 @@
import android.hardware.power.WorkDuration;
@VintfStability
-oneway interface IPowerHintSession {
+interface IPowerHintSession {
/**
* Updates the desired duration of a previously-created thread group.
*
@@ -29,7 +29,7 @@
*
* @param targetDurationNanos the new desired duration in nanoseconds
*/
- void updateTargetWorkDuration(long targetDurationNanos);
+ oneway void updateTargetWorkDuration(long targetDurationNanos);
/**
* Reports the actual duration of a thread group.
@@ -41,22 +41,22 @@
* @param actualDurationMicros how long the thread group took to complete its
* last task in nanoseconds
*/
- void reportActualWorkDuration(in WorkDuration[] durations);
+ oneway void reportActualWorkDuration(in WorkDuration[] durations);
/**
* Pause the session when the application is not allowed to send hint in framework.
*/
- void pause();
+ oneway void pause();
/**
* Resume the session when the application is allowed to send hint in framework.
*/
- void resume();
+ oneway void resume();
/**
* Close the session to release resources.
*/
- void close();
+ oneway void close();
/**
* Gives information to the PowerHintSession about upcoming or unexpected
@@ -64,5 +64,21 @@
*
* @param hint The hint to provide to the PowerHintSession
*/
- void sendHint(SessionHint hint);
+ oneway void sendHint(SessionHint hint);
+
+ /**
+ * Sets a list of threads to the power hint session. This operation will replace
+ * the current list of threads with the given list of threads. If there's already
+ * boost for the replaced threads, a reset must be performed for the replaced
+ * threads. Note that this is not an oneway method.
+ *
+ * @param threadIds The list of threads to be associated
+ * with this session.
+ *
+ * @throws ScopedAStatus Status of the operation. If status code is not
+ * STATUS_OK, getMessage() must be populated with the human-readable
+ * error message. If the list of thread ids is empty, EX_ILLEGAL_ARGUMENT
+ * must be thrown.
+ */
+ void setThreads(in int[] threadIds);
}
diff --git a/power/aidl/default/PowerHintSession.cpp b/power/aidl/default/PowerHintSession.cpp
index aa95be4..f395800 100644
--- a/power/aidl/default/PowerHintSession.cpp
+++ b/power/aidl/default/PowerHintSession.cpp
@@ -51,4 +51,12 @@
return ScopedAStatus::ok();
}
+ScopedAStatus PowerHintSession::setThreads(const std::vector<int32_t>& threadIds) {
+ if (threadIds.size() == 0) {
+ LOG(ERROR) << "Error: threadIds.size() shouldn't be " << threadIds.size();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ return ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/default/PowerHintSession.h b/power/aidl/default/PowerHintSession.h
index 6a7627a..1d74716 100644
--- a/power/aidl/default/PowerHintSession.h
+++ b/power/aidl/default/PowerHintSession.h
@@ -32,6 +32,7 @@
ndk::ScopedAStatus resume() override;
ndk::ScopedAStatus close() override;
ndk::ScopedAStatus sendHint(SessionHint hint) override;
+ ndk::ScopedAStatus setThreads(const std::vector<int32_t>& threadIds) override;
};
} // namespace aidl::android::hardware::power::impl::example
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index e51f756..5f5ce56 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -100,6 +100,10 @@
// target-level=7 compatibility_matrix file.
const uint64_t kCompatibilityMatrix7ApiLevel = 33;
+// DEVICEs launching with Android 14 MUST meet the requirements for the
+// target-level=8 compatibility_matrix file.
+const uint64_t kCompatibilityMatrix8ApiLevel = 34;
+
inline bool isUnknownOrUnsupported(const ndk::ScopedAStatus& status) {
return status.getStatus() == STATUS_UNKNOWN_TRANSACTION ||
status.getExceptionCode() == EX_UNSUPPORTED_OPERATION;
@@ -242,6 +246,27 @@
}
}
+TEST_P(PowerAidl, setThreads) {
+ std::shared_ptr<IPowerHintSession> session;
+ auto status = power->createHintSession(getpid(), getuid(), kSelfTids, 16666666L, &session);
+ if (mApiLevel < kCompatibilityMatrix7ApiLevel && !status.isOk()) {
+ EXPECT_TRUE(isUnknownOrUnsupported(status));
+ GTEST_SKIP() << "DEVICE not launching with Android 13 and beyond.";
+ }
+ ASSERT_TRUE(status.isOk());
+
+ if (mApiLevel < kCompatibilityMatrix8ApiLevel) {
+ GTEST_SKIP() << "DEVICE not launching with Android 14 and beyond.";
+ }
+
+ status = session->setThreads(kEmptyTids);
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
+
+ status = session->setThreads(kSelfTids);
+ ASSERT_TRUE(status.isOk());
+}
+
// FIXED_PERFORMANCE mode is required for all devices which ship on Android 11
// or later
TEST_P(PowerAidl, hasFixedPerformance) {
diff --git a/power/stats/aidl/OWNERS b/power/stats/aidl/OWNERS
index b290b49..e0d66d7 100644
--- a/power/stats/aidl/OWNERS
+++ b/power/stats/aidl/OWNERS
@@ -1,3 +1,4 @@
-bsschwar@google.com
+darrenhsu@google.com
+joaodias@google.com
krossmo@google.com
-tstrudel@google.com
+vincentwang@google.com
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 8911aea..9dbe09a 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -36,7 +36,7 @@
host_supported: true,
srcs: ["android/hardware/radio/config/*.aidl"],
stability: "vintf",
- imports: ["android.hardware.radio-V1"],
+ imports: ["android.hardware.radio-V2"],
backend: {
cpp: {
enabled: true,
@@ -60,7 +60,7 @@
host_supported: true,
srcs: ["android/hardware/radio/data/*.aidl"],
stability: "vintf",
- imports: ["android.hardware.radio-V1"],
+ imports: ["android.hardware.radio-V2"],
backend: {
cpp: {
enabled: true,
@@ -84,7 +84,7 @@
host_supported: true,
srcs: ["android/hardware/radio/messaging/*.aidl"],
stability: "vintf",
- imports: ["android.hardware.radio-V1"],
+ imports: ["android.hardware.radio-V2"],
backend: {
cpp: {
enabled: true,
@@ -108,7 +108,7 @@
host_supported: true,
srcs: ["android/hardware/radio/modem/*.aidl"],
stability: "vintf",
- imports: ["android.hardware.radio-V1"],
+ imports: ["android.hardware.radio-V2"],
backend: {
cpp: {
enabled: true,
@@ -132,7 +132,7 @@
host_supported: true,
srcs: ["android/hardware/radio/network/*.aidl"],
stability: "vintf",
- imports: ["android.hardware.radio-V1"],
+ imports: ["android.hardware.radio-V2"],
backend: {
cpp: {
enabled: true,
@@ -157,8 +157,8 @@
srcs: ["android/hardware/radio/sim/*.aidl"],
stability: "vintf",
imports: [
- "android.hardware.radio-V1",
- "android.hardware.radio.config",
+ "android.hardware.radio-V2",
+ "android.hardware.radio.config-V2",
],
backend: {
cpp: {
@@ -186,7 +186,7 @@
host_supported: true,
srcs: ["android/hardware/radio/voice/*.aidl"],
stability: "vintf",
- imports: ["android.hardware.radio-V1"],
+ imports: ["android.hardware.radio-V2"],
backend: {
cpp: {
enabled: true,
@@ -209,8 +209,10 @@
vendor_available: true,
srcs: ["android/hardware/radio/ims/media/*.aidl"],
stability: "vintf",
- imports: ["android.hardware.radio-V1",
- "android.hardware.radio.data-V1"],
+ imports: [
+ "android.hardware.radio-V2",
+ "android.hardware.radio.data-V2",
+ ],
backend: {
cpp: {
enabled: false,
@@ -226,7 +228,7 @@
vendor_available: true,
srcs: ["android/hardware/radio/ims/*.aidl"],
stability: "vintf",
- imports: ["android.hardware.radio-V1"],
+ imports: ["android.hardware.radio-V2"],
backend: {
cpp: {
enabled: false,
@@ -236,4 +238,3 @@
},
},
}
-
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
index 41eff51..74dc39d 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModem.aidl
@@ -41,9 +41,18 @@
oneway void getModemActivityInfo(in int serial);
oneway void getModemStackStatus(in int serial);
oneway void getRadioCapability(in int serial);
+ /**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ */
oneway void nvReadItem(in int serial, in android.hardware.radio.modem.NvItem itemId);
oneway void nvResetConfig(in int serial, in android.hardware.radio.modem.ResetNvType resetType);
+ /**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ */
oneway void nvWriteCdmaPrl(in int serial, in byte[] prl);
+ /**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ */
oneway void nvWriteItem(in int serial, in android.hardware.radio.modem.NvWriteItem item);
oneway void requestShutdown(in int serial);
oneway void responseAcknowledgement();
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
index dcaff45..af8bbe1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/IRadioModemResponse.aidl
@@ -42,9 +42,18 @@
oneway void getModemActivityInfoResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.modem.ActivityStatsInfo activityInfo);
oneway void getModemStackStatusResponse(in android.hardware.radio.RadioResponseInfo info, in boolean isEnabled);
oneway void getRadioCapabilityResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.modem.RadioCapability rc);
+ /**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ */
oneway void nvReadItemResponse(in android.hardware.radio.RadioResponseInfo info, in String result);
oneway void nvResetConfigResponse(in android.hardware.radio.RadioResponseInfo info);
+ /**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ */
oneway void nvWriteCdmaPrlResponse(in android.hardware.radio.RadioResponseInfo info);
+ /**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ */
oneway void nvWriteItemResponse(in android.hardware.radio.RadioResponseInfo info);
oneway void requestShutdownResponse(in android.hardware.radio.RadioResponseInfo info);
oneway void sendDeviceStateResponse(in android.hardware.radio.RadioResponseInfo info);
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl
index 3e27643..b80d7ac 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvItem.aidl
@@ -32,6 +32,9 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.radio.modem;
+/**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ */
@Backing(type="int") @JavaDerive(toString=true) @VintfStability
enum NvItem {
CDMA_MEID = 1,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl
index 17b7de0..6a786bc 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.modem/current/android/hardware/radio/modem/NvWriteItem.aidl
@@ -32,6 +32,9 @@
// later when a module using the interface is updated, e.g., Mainline modules.
package android.hardware.radio.modem;
+/**
+ * @deprecated NV APIs are deprecated starting from Android U.
+ */
@JavaDerive(toString=true) @VintfStability
parcelable NvWriteItem {
android.hardware.radio.modem.NvItem itemId;
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
index c115c86..9761900 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
@@ -41,6 +41,9 @@
oneway void getCdmaRoamingPreference(in int serial);
oneway void getCellInfoList(in int serial);
oneway void getDataRegistrationState(in int serial);
+ /**
+ * @deprecated Deprecated starting from Android U.
+ */
oneway void getImsRegistrationState(in int serial);
oneway void getNetworkSelectionMode(in int serial);
oneway void getOperator(in int serial);
@@ -74,4 +77,7 @@
oneway void triggerEmergencyNetworkScan(int serial, in android.hardware.radio.network.EmergencyNetworkScanTrigger request);
oneway void cancelEmergencyNetworkScan(int serial, boolean resetScan);
oneway void exitEmergencyMode(in int serial);
+ oneway void setNullCipherAndIntegrityEnabled(in int serial, in boolean enabled);
+ oneway void isN1ModeEnabled(in int serial);
+ oneway void setN1ModeEnabled(in int serial, boolean enable);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
index 24d587e..c228bc1 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -42,6 +42,9 @@
oneway void getCdmaRoamingPreferenceResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.CdmaRoamingType type);
oneway void getCellInfoListResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.CellInfo[] cellInfo);
oneway void getDataRegistrationStateResponse(in android.hardware.radio.RadioResponseInfo info, in android.hardware.radio.network.RegStateResult dataRegResponse);
+ /**
+ * @deprecated Deprecated starting from Android U.
+ */
oneway void getImsRegistrationStateResponse(in android.hardware.radio.RadioResponseInfo info, in boolean isRegistered, in android.hardware.radio.RadioTechnologyFamily ratFamily);
oneway void getNetworkSelectionModeResponse(in android.hardware.radio.RadioResponseInfo info, in boolean manual);
oneway void getOperatorResponse(in android.hardware.radio.RadioResponseInfo info, in String longName, in String shortName, in String numeric);
@@ -73,4 +76,7 @@
oneway void triggerEmergencyNetworkScanResponse(in android.hardware.radio.RadioResponseInfo info);
oneway void exitEmergencyModeResponse(in android.hardware.radio.RadioResponseInfo info);
oneway void cancelEmergencyNetworkScanResponse(in android.hardware.radio.RadioResponseInfo info);
+ oneway void setNullCipherAndIntegrityEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
+ oneway void isN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info, boolean isEnabled);
+ oneway void setN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
index ecc2a9b..afc4f4e 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
@@ -53,6 +53,9 @@
GSM = 65536,
TD_SCDMA = 131072,
IWLAN = 262144,
+ /**
+ * @deprecated use LTE instead.
+ */
LTE_CA = 524288,
NR = 1048576,
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
index 9dad0a4..7060469 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
@@ -53,6 +53,9 @@
GSM = 16,
TD_SCDMA = 17,
IWLAN = 18,
+ /**
+ * @deprecated use LTE instead and indicate carrier aggregation through multiple physical channel configurations in IRadioNetwork::currentPhysicalChannelConfigs.
+ */
LTE_CA = 19,
NR = 20,
}
diff --git a/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl b/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
index 6cd0a95..edf33ba 100644
--- a/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
+++ b/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
@@ -41,6 +41,7 @@
GSM = 1 << RadioTechnology.GSM,
TD_SCDMA = 1 << RadioTechnology.TD_SCDMA,
IWLAN = 1 << RadioTechnology.IWLAN,
+ /** @deprecated use LTE instead. */
LTE_CA = 1 << RadioTechnology.LTE_CA,
/**
* 5G NR. This is only use in 5G Standalone mode.
diff --git a/radio/aidl/android/hardware/radio/RadioError.aidl b/radio/aidl/android/hardware/radio/RadioError.aidl
index ae58a0e..61d5a77 100644
--- a/radio/aidl/android/hardware/radio/RadioError.aidl
+++ b/radio/aidl/android/hardware/radio/RadioError.aidl
@@ -41,6 +41,9 @@
* Operation requires SIM PUK2 to be entered
*/
SIM_PUK2 = 5,
+ /**
+ * Optional API
+ */
REQUEST_NOT_SUPPORTED = 6,
CANCELLED = 7,
/**
diff --git a/radio/aidl/android/hardware/radio/RadioTechnology.aidl b/radio/aidl/android/hardware/radio/RadioTechnology.aidl
index 917cb16..4b51152 100644
--- a/radio/aidl/android/hardware/radio/RadioTechnology.aidl
+++ b/radio/aidl/android/hardware/radio/RadioTechnology.aidl
@@ -45,6 +45,10 @@
GSM,
TD_SCDMA,
IWLAN,
+ /**
+ * @deprecated use LTE instead and indicate carrier aggregation through multiple
+ * physical channel configurations in IRadioNetwork::currentPhysicalChannelConfigs.
+ */
LTE_CA,
/**
* 5G NR. This is only used in 5G Standalone mode.
diff --git a/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl b/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
index 929f02d..0d36bbd 100644
--- a/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
+++ b/radio/aidl/android/hardware/radio/config/IRadioConfigResponse.aidl
@@ -54,7 +54,6 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void getNumOfLiveModemsResponse(
in android.hardware.radio.RadioResponseInfo info, in byte numOfLiveModems);
@@ -93,7 +92,6 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_ARGUMENTS
*/
void setNumOfLiveModemsResponse(in android.hardware.radio.RadioResponseInfo info);
diff --git a/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl b/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
index 88b6c1b..06c83c1 100644
--- a/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
+++ b/radio/aidl/android/hardware/radio/data/IRadioDataResponse.aidl
@@ -44,7 +44,6 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
* RadioError:NO_RESOURCES- Indicates that no pdu session ids are available
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void allocatePduSessionIdResponse(in RadioResponseInfo info, in int id);
@@ -57,7 +56,6 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
* RadioError:NO_RESOURCES
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_CALL_ID
*/
void cancelHandoverResponse(in RadioResponseInfo info);
@@ -66,7 +64,6 @@
* @param info Response info struct containing response type, serial no. and error
*
* Valid errors returned:
- * RadioError:REQUEST_NOT_SUPPORTED may be returned when HAL 1.2 or higher is supported.
* RadioError:NONE indicates success. Any other error will remove the network from the list.
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INVALID_CALL_ID
@@ -112,7 +109,6 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
* RadioError:NO_RESOURCES
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void releasePduSessionIdResponse(in RadioResponseInfo info);
@@ -131,7 +127,6 @@
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void setDataAllowedResponse(in RadioResponseInfo info);
@@ -146,7 +141,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:SIM_ABSENT
*/
void setDataProfileResponse(in RadioResponseInfo info);
@@ -159,7 +153,6 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:MODEM_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void setDataThrottlingResponse(in RadioResponseInfo info);
@@ -176,7 +169,6 @@
* RadioError:MODEM_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:NOT_PROVISIONED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -208,7 +200,6 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
* RadioError:NO_RESOURCES
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_CALL_ID
*/
void startHandoverResponse(in RadioResponseInfo info);
diff --git a/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl b/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl
index b5e7680..241c342 100644
--- a/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl
+++ b/radio/aidl/android/hardware/radio/ims/IRadioImsResponse.aidl
@@ -37,7 +37,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
*/
void setSrvccCallInfoResponse(in RadioResponseInfo info);
@@ -54,7 +53,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
*/
void updateImsRegistrationInfoResponse(in RadioResponseInfo info);
@@ -72,7 +70,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
*/
void startImsTrafficResponse(in RadioResponseInfo info,
@@ -90,7 +87,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
*/
void stopImsTrafficResponse(in RadioResponseInfo info);
@@ -107,7 +103,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
*/
void triggerEpsFallbackResponse(in RadioResponseInfo info);
@@ -124,7 +119,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
*/
void sendAnbrQueryResponse(in RadioResponseInfo info);
@@ -141,7 +135,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
*/
void updateImsCallStatusResponse(in RadioResponseInfo info);
diff --git a/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl b/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
index 492755f..8cbc869 100644
--- a/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/IRadioMessagingResponse.aidl
@@ -36,7 +36,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void acknowledgeIncomingGsmSmsWithPduResponse(in RadioResponseInfo info);
@@ -56,7 +55,6 @@
* RadioError:NETWORK_NOT_READY
* RadioError:INVALID_MODEM_STATE
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -73,7 +71,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void acknowledgeLastIncomingGsmSmsResponse(in RadioResponseInfo info);
@@ -98,7 +95,6 @@
* RadioError:MODEM_ERR
* RadioError:NO_SUCH_ENTRY
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -122,7 +118,6 @@
* RadioError:NO_SUCH_ENTRY
* RadioError:INTERNAL_ERR
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
@@ -145,7 +140,6 @@
* RadioError:MODEM_ERR
* RadioError:NO_RESOURCES
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
@@ -168,7 +162,6 @@
* RadioError:MODEM_ERR
* RadioError:NO_RESOURCES
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
@@ -191,7 +184,6 @@
* RadioError:MODEM_ERR
* RadioError:INVALID_MODEM_STATE
* RadioError:NOT_PROVISIONED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -212,7 +204,6 @@
* RadioError:MODEM_ERR
* RadioError:INVALID_STATE
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:SIM_ABSENT
@@ -240,7 +231,6 @@
* RadioError:MODEM_ERR
* RadioError:NETWORK_ERR
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NETWORK_NOT_READY
* RadioError:OPERATION_NOT_ALLOWED
@@ -275,7 +265,6 @@
* RadioError:INVALID_SMSC_ADDRESS
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:ENCODING_ERR
* RadioError:NO_RESOURCES
@@ -308,7 +297,6 @@
* RadioError:ENCODING_ERR
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NETWORK_NOT_READY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -336,7 +324,6 @@
* RadioError:MODEM_ERR
* RadioError:NETWORK_ERR
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NETWORK_NOT_READY
* RadioError:OPERATION_NOT_ALLOWED
@@ -368,7 +355,6 @@
* RadioError:MODEM_ERR
* RadioError:NETWORK_ERR
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NETWORK_NOT_READY
* RadioError:OPERATION_NOT_ALLOWED
@@ -393,7 +379,6 @@
* RadioError:SYSTEM_ERR
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -414,7 +399,6 @@
* RadioError:SYSTEM_ERR
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
@@ -434,7 +418,6 @@
* RadioError:SYSTEM_ERR
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -455,7 +438,6 @@
* RadioError:SYSTEM_ERR
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
@@ -476,7 +458,6 @@
* RadioError:MODEM_ERR
* RadioError:NO_RESOURCES
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -502,7 +483,6 @@
* RadioError:INVALID_MODEM_STATE
* RadioError:INVALID_SMSC_ADDRESS
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -531,7 +511,6 @@
* RadioError:INVALID_SMSC_ADDRESS
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
* RadioError:SIM_ABSENT
diff --git a/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
index ba0ddb9..a5d98d3 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModem.aidl
@@ -117,6 +117,8 @@
* @param itemId NvItem
*
* Response function is IRadioModemResponse.nvReadItemResponse()
+ *
+ * @deprecated NV APIs are deprecated starting from Android U.
*/
void nvReadItem(in int serial, in NvItem itemId);
@@ -128,6 +130,8 @@
* @param resetType ResetNvType
*
* Response function is IRadioModemResponse.nvResetConfigResponse()
+ *
+ * Note: This will be deprecated in favor of a rebootModem API in Android U.
*/
void nvResetConfig(in int serial, in ResetNvType resetType);
@@ -139,6 +143,8 @@
* @param prl PRL as a byte array
*
* Response function is IRadioModemResponse.nvWriteCdmaPrlResponse()
+ *
+ * @deprecated NV APIs are deprecated starting from Android U.
*/
void nvWriteCdmaPrl(in int serial, in byte[] prl);
@@ -150,6 +156,8 @@
* @param item NvWriteItem
*
* Response function is IRadioModemResponse.nvWriteItemResponse()
+ *
+ * @deprecated NV APIs are deprecated starting from Android U.
*/
void nvWriteItem(in int serial, in NvWriteItem item);
diff --git a/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl b/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
index b17cac4..eca3192 100644
--- a/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
+++ b/radio/aidl/android/hardware/radio/modem/IRadioModemResponse.aidl
@@ -61,7 +61,6 @@
* RadioError:SYSTEM_ERR
* RadioError:MODEM_ERR
* RadioError:NOT_PROVISIONED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -88,7 +87,6 @@
* RadioError:NOT_PROVISIONED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void getDeviceIdentityResponse(in RadioResponseInfo info, in String imei, in String imeisv,
in String esn, in String meid);
@@ -100,7 +98,6 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void getHardwareConfigResponse(in RadioResponseInfo info, in HardwareConfig[] config);
@@ -118,7 +115,6 @@
* RadioError:NOT_PROVISIONED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void getModemActivityInfoResponse(in RadioResponseInfo info, in ActivityStatsInfo activityInfo);
@@ -141,7 +137,6 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:INVALID_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INTERNAL_ERR
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
@@ -156,7 +151,8 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
+ *
+ * @deprecated NV APIs are deprecated starting from Android U.
*/
void nvReadItemResponse(in RadioResponseInfo info, in String result);
@@ -166,7 +162,8 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
+ *
+ * Note: This will be deprecated in favor of a rebootModemResponse API in Android U.
*/
void nvResetConfigResponse(in RadioResponseInfo info);
@@ -176,7 +173,8 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
+ *
+ * @deprecated NV APIs are deprecated starting from Android U.
*/
void nvWriteCdmaPrlResponse(in RadioResponseInfo info);
@@ -186,7 +184,8 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
+ *
+ * @deprecated NV APIs are deprecated starting from Android U.
*/
void nvWriteItemResponse(in RadioResponseInfo info);
@@ -200,7 +199,6 @@
* RadioError:NO_MEMORY
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -216,7 +214,6 @@
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -237,7 +234,6 @@
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
* RadioError:INVALID_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
diff --git a/radio/aidl/android/hardware/radio/modem/NvItem.aidl b/radio/aidl/android/hardware/radio/modem/NvItem.aidl
index 649b0d2..310b1ad 100644
--- a/radio/aidl/android/hardware/radio/modem/NvItem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/NvItem.aidl
@@ -16,6 +16,7 @@
package android.hardware.radio.modem;
+/** @deprecated NV APIs are deprecated starting from Android U. */
@VintfStability
@Backing(type="int")
@JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl b/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl
index 47fb490..6472f23 100644
--- a/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl
+++ b/radio/aidl/android/hardware/radio/modem/NvWriteItem.aidl
@@ -18,6 +18,7 @@
import android.hardware.radio.modem.NvItem;
+/** @deprecated NV APIs are deprecated starting from Android U. */
@VintfStability
@JavaDerive(toString=true)
parcelable NvWriteItem {
diff --git a/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl b/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl
index 16487f8..6476fe8 100644
--- a/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl
+++ b/radio/aidl/android/hardware/radio/modem/ResetNvType.aidl
@@ -16,6 +16,7 @@
package android.hardware.radio.modem;
+/** Note: This will be deprecated along with nvResetConfig in Android U. */
@VintfStability
@Backing(type="int")
@JavaDerive(toString=true)
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
index 574798a..4d35742 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
@@ -112,6 +112,8 @@
* @param serial Serial number of request.
*
* Response function is IRadioNetworkResponse.getImsRegistrationStateResponse()
+ *
+ * @deprecated Deprecated starting from Android U.
*/
void getImsRegistrationState(in int serial);
@@ -482,4 +484,50 @@
* Response function is IRadioEmergencyResponse.exitEmergencyModeResponse()
*/
void exitEmergencyMode(in int serial);
+
+ /**
+ * Set if null encryption and integrity modes are enabled. If the value of enabled is false
+ * the modem must not allow any network communications with null ciphering or null integrity
+ * modes. In case of an emergency call, the modem must bypass this setting.
+ *
+ * Null ciphering and integrity modes include (but are not limited to):
+ * 2G: A5/0
+ * 3G: UEA0 and UIA0
+ * 4G: EEA0 and EIA0
+ * 5G: NEA0 and NIA0
+ *
+ *
+ * @param serial Serial number of the request.
+ * @param enabled To allow null encryption/integrity, set to true.
+ * Otherwise, false.
+ *
+ * Response callback is IRadioResponse.setNullCipherAndIntegrityEnabledResponse()
+ */
+ void setNullCipherAndIntegrityEnabled(in int serial, in boolean enabled);
+
+ /**
+ * Checks whether N1 mode (access to 5G core network) is enabled or not.
+ *
+ * @param serial Serial number of request.
+ *
+ * Response function is IRadioNetworkResponse.isN1ModeEnabledResponse()
+ */
+ void isN1ModeEnabled(in int serial);
+
+ /**
+ * Enables or disables N1 mode (access to 5G core network) in accordance with
+ * 3GPP TS 24.501 4.9.
+ *
+ * Note: The default value of N1 mode shall be based on the modem's internal configuration
+ * as per device or carrier. This API may be invoked on demand first to disable N1 mode and
+ * later to re-enable for certain use case. This setting shall not be persisted by modem.
+ * This setting shall not interfere with the allowed network type bitmap set using
+ * {@link IRadioNetwork#setAllowedNetworkTypesBitmap()} API.
+ *
+ * @param serial Serial number of request.
+ * @param enable {@code true} to enable N1 mode, {@code false} to disable N1 mode.
+ *
+ * Response function is IRadioNetworkResponse.setN1ModeEnabledResponse()
+ */
+ void setN1ModeEnabled(in int serial, boolean enable);
}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index fc4db2c..3802bd6 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -57,7 +57,6 @@
* RadioError:INTERNAL_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
*/
void getAllowedNetworkTypesBitmapResponse(in RadioResponseInfo info, in int networkTypeBitmap);
@@ -74,7 +73,6 @@
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -93,7 +91,6 @@
* RadioError:INTERNAL_ERR
* RadioError:NO_MEMORY
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:CANCELLED
* RadioError:NO_RESOURCES
* RadioError:INTERNAL_ERR
@@ -126,7 +123,6 @@
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:SIM_ABSENT
@@ -170,7 +166,8 @@
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
+ *
+ * @deprecated Deprecated starting from Android U.
*/
void getImsRegistrationStateResponse(
in RadioResponseInfo info, in boolean isRegistered, in RadioTechnologyFamily ratFamily);
@@ -187,7 +184,6 @@
* RadioError:SYSTEM_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -205,7 +201,6 @@
* RadioError:NO_MEMORY
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -247,7 +242,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void getVoiceRadioTechnologyResponse(in RadioResponseInfo info, in RadioTechnology rat);
@@ -272,7 +266,6 @@
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void isNrDualConnectivityEnabledResponse(in RadioResponseInfo info, in boolean isEnabled);
@@ -287,7 +280,6 @@
* RadioError:INTERNAL_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
*/
void setAllowedNetworkTypesBitmapResponse(in RadioResponseInfo info);
@@ -304,7 +296,6 @@
* RadioError:SYSTEM_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -325,7 +316,6 @@
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
* RadioError:FDN_CHECK_FAILURE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -342,7 +332,6 @@
* RadioError:SYSTEM_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -362,7 +351,6 @@
* RadioError:INVALID_ARGUMENTS
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void setCellInfoListRateResponse(in RadioResponseInfo info);
@@ -400,7 +388,6 @@
* RadioError:SYSTEM_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:SIM_ABSENT
@@ -420,7 +407,6 @@
* RadioError:SYSTEM_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*
@@ -443,7 +429,6 @@
* RadioError:SYSTEM_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*
@@ -459,7 +444,6 @@
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_STATE
*/
void setNrDualConnectivityStateResponse(in RadioResponseInfo info);
@@ -486,7 +470,6 @@
* RadioError:SYSTEM_ERR
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:SIM_ABSENT
@@ -543,7 +526,6 @@
* RadioError:INVALID_ARGUMENTS
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:SIM_ABSENT
*/
void supplyNetworkDepersonalizationResponse(in RadioResponseInfo info, in int remainingRetries);
@@ -632,4 +614,44 @@
* RadioError:MODEM_ERR
*/
void cancelEmergencyNetworkScanResponse(in RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:MODEM_ERR
+ */
+ void setNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info);
+
+ /**
+ * Response of isN1ModeEnabled.
+ * This is an optional API.
+ *
+ * @param info Response info struct containing response type, serial no. and error.
+ * @param isEnabled Indicates whether N1 mode is enabled or not.
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ * RadioError:REQUEST_NOT_SUPPORTED
+ */
+ void isN1ModeEnabledResponse(in RadioResponseInfo info, boolean isEnabled);
+
+ /**
+ * Response of setN1ModeEnabled.
+ * This is an optional API.
+ *
+ * @param info Response info struct containing response type, serial no. and error.
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:INVALID_STATE
+ */
+ void setN1ModeEnabledResponse(in RadioResponseInfo info);
}
diff --git a/radio/aidl/android/hardware/radio/network/RegStateResult.aidl b/radio/aidl/android/hardware/radio/network/RegStateResult.aidl
index 3d96b8c..f1d2972 100644
--- a/radio/aidl/android/hardware/radio/network/RegStateResult.aidl
+++ b/radio/aidl/android/hardware/radio/network/RegStateResult.aidl
@@ -33,9 +33,9 @@
*/
RegState regState;
/**
- * Indicates the radio technology (except LTE_CA, which is no longer a valid value), which
- * must not be UNKNOWN if regState is REG_HOME, REG_ROAMING, NOT_REG_MT_NOT_SEARCHING_OP_EM,
- * NOT_REG_MT_SEARCHING_OP_EM, REG_DENIED_EM, or UNKNOWN_EM.
+ * Indicates the radio technology, which must not be UNKNOWN if regState is REG_HOME,
+ * REG_ROAMING, NOT_REG_MT_NOT_SEARCHING_OP_EM, NOT_REG_MT_SEARCHING_OP_EM, REG_DENIED_EM,
+ * or UNKNOWN_EM.
* When the device is on carrier aggregation, vendor RIL service must properly report multiple
* PhysicalChannelConfig elements through IRadioNetwork::currentPhysicalChannelConfigs.
*/
diff --git a/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl b/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
index 750a29a..b3df504 100644
--- a/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
+++ b/radio/aidl/android/hardware/radio/sim/IRadioSimResponse.aidl
@@ -65,7 +65,6 @@
* RadioError:CANCELLED
* RadioError:INVALID_ARGUMENTS
* RadioError:INVALID_SIM_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:SIM_PUK2
*/
void changeIccPin2ForAppResponse(in RadioResponseInfo info, in int remainingRetries);
@@ -84,7 +83,6 @@
* RadioError:CANCELLED
* RadioError:INVALID_ARGUMENTS
* RadioError:INVALID_SIM_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void changeIccPinForAppResponse(in RadioResponseInfo info, in int remainingRetries);
@@ -108,7 +106,6 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void getAllowedCarriersResponse(in RadioResponseInfo info, in CarrierRestrictions carriers,
in SimLockMultiSimPolicy multiSimPolicy);
@@ -133,7 +130,6 @@
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
* RadioError:NOT_PROVISIONED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:SIM_ABSENT
@@ -153,7 +149,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:SIM_ABSENT
*/
void getCdmaSubscriptionSourceResponse(
@@ -176,7 +171,6 @@
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
* RadioError:FDN_CHECK_FAILURE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -191,7 +185,6 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
* RadioError:NO_RESOURCES
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void getIccCardStatusResponse(in RadioResponseInfo info, in CardStatus cardStatus);
@@ -208,7 +201,6 @@
* RadioError:CANCELLED
* RadioError:INVALID_SIM_STATE
* RadioError:SIM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void getImsiForAppResponse(in RadioResponseInfo info, in String imsi);
@@ -219,13 +211,10 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_ARGUMENTS
* RadioError:INVALID_SIM_STATE
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
- * REQUEST_NOT_SUPPORTED may only be returned on devices that don't support this API,
- * indicated by the HAL capability CAPABILITY_SIM_PHONEBOOK_IN_MODEM.
*/
void getSimPhonebookCapacityResponse(in RadioResponseInfo info, in PhonebookCapacity capacity);
@@ -235,13 +224,10 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_ARGUMENTS
* RadioError:INVALID_SIM_STATE
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
- * REQUEST_NOT_SUPPORTED may only be returned on devices that don't support this API,
- * indicated by the HAL capability CAPABILITY_SIM_PHONEBOOK_IN_MODEM.
*/
void getSimPhonebookRecordsResponse(in RadioResponseInfo info);
@@ -255,7 +241,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void iccCloseLogicalChannelResponse(in RadioResponseInfo info);
@@ -274,7 +259,6 @@
* RadioError:CANCELLED
* RadioError:INVALID_SIM_STATE
* RadioError:SIM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void iccIoForAppResponse(in RadioResponseInfo info, in IccIoResult iccIo);
@@ -296,7 +280,6 @@
* RadioError:SIM_ERR
* RadioError:INVALID_SIM_STATE
* RadioError:MISSING_RESOURCE
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void iccOpenLogicalChannelResponse(
in RadioResponseInfo info, in int channelId, in byte[] selectResponse);
@@ -312,7 +295,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void iccTransmitApduBasicChannelResponse(in RadioResponseInfo info, in IccIoResult result);
@@ -327,7 +309,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void iccTransmitApduLogicalChannelResponse(in RadioResponseInfo info, in IccIoResult result);
@@ -341,7 +322,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void reportStkServiceIsRunningResponse(in RadioResponseInfo info);
@@ -359,7 +339,6 @@
* RadioError:INVALID_MODEM_STATE
* RadioError:SIM_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void requestIccSimAuthenticationResponse(in RadioResponseInfo info, in IccIoResult result);
@@ -379,7 +358,6 @@
* RadioError:CANCELLED
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:SIM_ABSENT
*/
void sendEnvelopeResponse(in RadioResponseInfo info, in String commandResponse);
@@ -397,7 +375,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:SIM_ABSENT
*/
void sendEnvelopeWithStatusResponse(in RadioResponseInfo info, in IccIoResult iccIo);
@@ -415,7 +392,6 @@
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:SIM_ABSENT
*/
void sendTerminalResponseToSimResponse(in RadioResponseInfo info);
@@ -427,7 +403,6 @@
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void setAllowedCarriersResponse(in RadioResponseInfo info);
@@ -435,12 +410,11 @@
* @param info Response info struct containing response type, serial no. and error
*
* Valid errors returned:
- * RadioError:RIL_E_SUCCESS
- * RadioError:RIL_E_RADIO_NOT_AVAILABLE
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
* RadioError:SIM_ABSENT
- * RadioError:RIL_E_REQUEST_NOT_SUPPORTED
* RadioError:INVALID_ARGUMENTS
- * RadioError:MODEM_INTERNAL_FAILURE
+ * RadioError:INTERNAL_FAILURE
*/
void setCarrierInfoForImsiEncryptionResponse(in RadioResponseInfo info);
@@ -456,7 +430,6 @@
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void setCdmaSubscriptionSourceResponse(in RadioResponseInfo info);
@@ -477,7 +450,6 @@
* RadioError:SYSTEM_ERR
* RadioError:INVALID_STATE
* RadioError:FDN_CHECK_FAILURE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -507,7 +479,6 @@
* RadioError:SYSTEM_ERR
* RadioError:MODEM_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -527,7 +498,6 @@
* RadioError:CANCELLED
* RadioError:INVALID_ARGUMENTS
* RadioError:INVALID_SIM_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:SIM_PUK2
*/
void supplyIccPin2ForAppResponse(in RadioResponseInfo info, in int remainingRetries);
@@ -546,7 +516,6 @@
* RadioError:CANCELLED
* RadioError:INVALID_ARGUMENTS
* RadioError:INVALID_SIM_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void supplyIccPinForAppResponse(in RadioResponseInfo info, in int remainingRetries);
@@ -564,7 +533,6 @@
* RadioError:CANCELLED
* RadioError:INVALID_ARGUMENTS
* RadioError:INVALID_SIM_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void supplyIccPuk2ForAppResponse(in RadioResponseInfo info, in int remainingRetries);
@@ -582,7 +550,6 @@
* RadioError:CANCELLED
* RadioError:INVALID_ARGUMENTS
* RadioError:INVALID_SIM_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void supplyIccPukForAppResponse(in RadioResponseInfo info, in int remainingRetries);
@@ -603,7 +570,6 @@
* RadioError:MODEM_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:NO_RESOURCES
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void supplySimDepersonalizationResponse(
in RadioResponseInfo info, in PersoSubstate persoType, in int remainingRetries);
@@ -616,7 +582,6 @@
* Valid errors returned:
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_ARGUMENTS
* RadioError:INVALID_SIM_STATE
* RadioError:MODEM_ERR
@@ -624,8 +589,6 @@
* RadioError:SIM_ERR
* RadioError:NO_SUCH_ENTRY
* RadioError:NO_RESOURCES
- * REQUEST_NOT_SUPPORTED may only be returned on devices that don't support this API,
- * indicated by the HAL capability CAPABILITY_SIM_PHONEBOOK_IN_MODEM.
*/
void updateSimPhonebookRecordsResponse(in RadioResponseInfo info, in int updatedRecordIndex);
}
diff --git a/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl b/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl
index cf1b953..39e3ace 100644
--- a/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl
+++ b/radio/aidl/android/hardware/radio/voice/IRadioVoiceResponse.aidl
@@ -42,7 +42,6 @@
* RadioError:INVALID_CALL_ID
* RadioError:INVALID_ARGUMENTS
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -71,7 +70,6 @@
* RadioError:INVALID_STATE
* RadioError:INVALID_ARGUMENTS
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -92,7 +90,6 @@
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:INVALID_ARGUMENTS
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -122,7 +119,6 @@
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:ABORTED
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:CANCELLED
*/
@@ -163,7 +159,6 @@
* RadioError:SYSTEM_ERR
* RadioError:INVALID_ARGUMENTS
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:SIM_ABSENT
@@ -185,7 +180,6 @@
* RadioError:INTERNAL_ERR
* RadioError:INVALID_CALL_ID
* RadioError:OPERATION_NOT_ALLOWED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -212,7 +206,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:FDN_CHECK_FAILURE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:SYSTEM_ERR
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -241,7 +234,6 @@
* RadioError:FDN_CHECK_FAILURE
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -260,7 +252,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:FDN_CHECK_FAILURE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -282,7 +273,6 @@
* RadioError:INTERNAL_ERR
* RadioError:FDN_CHECK_FAILURE
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_ARGUMENTS
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -298,7 +288,6 @@
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
* RadioError:INVALID_ARGUMENTS
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -344,7 +333,6 @@
* RadioError:INVALID_ARGUMENTS
* RadioError:INTERNAL_ERR
* RadioError:MODEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_MEMORY
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -367,7 +355,6 @@
* RadioError:INVALID_ARGUMENTS
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -386,7 +373,6 @@
* RadioError:INTERNAL_ERR
* RadioError:NO_MEMORY
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -404,7 +390,6 @@
* RadioError:INTERNAL_ERR
* RadioError:NO_MEMORY
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -423,7 +408,6 @@
* RadioError:INVALID_ARGUMENTS
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:SIM_ABSENT
*/
void handleStkCallSetupRequestFromSimResponse(in RadioResponseInfo info);
@@ -442,7 +426,6 @@
* RadioError:INVALID_CALL_ID
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void hangupConnectionResponse(in RadioResponseInfo info);
@@ -461,7 +444,6 @@
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:INVALID_ARGUMENTS
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -482,7 +464,6 @@
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:INVALID_ARGUMENTS
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:CANCELLED
*/
void hangupWaitingOrBackgroundResponse(in RadioResponseInfo info);
@@ -497,7 +478,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:NO_MEMORY
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void isVoNrEnabledResponse(in RadioResponseInfo info, in boolean enable);
@@ -516,7 +496,6 @@
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:INVALID_ARGUMENTS
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -536,7 +515,6 @@
* RadioError:MODEM_ERR
* RadioError:INVALID_CALL_ID
* RadioError:INVALID_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
@@ -557,7 +535,6 @@
* RadioError:MODEM_ERR
* RadioError:INVALID_CALL_ID
* RadioError:INVALID_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -578,7 +555,6 @@
* RadioError:INVALID_CALL_ID
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
*/
@@ -603,7 +579,6 @@
* RadioError:ABORTED
* RadioError:SYSTEM_ERR
* RadioError:INVALID_STATE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -625,7 +600,6 @@
* RadioError:INTERNAL_ERR
* RadioError:INVALID_CALL_ID
* RadioError:OPERATION_NOT_ALLOWED
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:CANCELLED
*/
@@ -647,7 +621,6 @@
* RadioError:INTERNAL_ERR
* RadioError:INVALID_STATE
* RadioError:FDN_CHECK_FAILURE
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -670,7 +643,6 @@
* RadioError:INVALID_STATE
* RadioError:FDN_CHECK_FAILURE
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -690,7 +662,6 @@
* RadioError:NO_MEMORY
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -707,7 +678,6 @@
* RadioError:REQUEST_RATE_LIMITED
* RadioError:INTERNAL_ERR
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -724,7 +694,6 @@
* RadioError:INTERNAL_ERR
* RadioError:NO_MEMORY
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_CALL_ID
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
@@ -742,7 +711,6 @@
* RadioError:INTERNAL_ERR
* RadioError:NO_MEMORY
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
*/
@@ -758,7 +726,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:NO_MEMORY
- * RadioError:REQUEST_NOT_SUPPORTED
*/
void setVoNrEnabledResponse(in RadioResponseInfo info);
@@ -776,7 +743,6 @@
* RadioError:INTERNAL_ERR
* RadioError:INVALID_CALL_ID
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
*/
@@ -796,7 +762,6 @@
* RadioError:MODEM_ERR
* RadioError:INTERNAL_ERR
* RadioError:INVALID_CALL_ID
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:CANCELLED
* RadioError:INVALID_MODEM_STATE
*/
@@ -817,7 +782,6 @@
* RadioError:OPERATION_NOT_ALLOWED
* RadioError:INVALID_ARGUMENTS
* RadioError:SYSTEM_ERR
- * RadioError:REQUEST_NOT_SUPPORTED
* RadioError:INVALID_MODEM_STATE
* RadioError:NO_RESOURCES
* RadioError:CANCELLED
diff --git a/radio/aidl/compat/libradiocompat/Android.bp b/radio/aidl/compat/libradiocompat/Android.bp
index f79e045..c40ca30 100644
--- a/radio/aidl/compat/libradiocompat/Android.bp
+++ b/radio/aidl/compat/libradiocompat/Android.bp
@@ -31,17 +31,18 @@
"-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
],
shared_libs: [
- "android.hardware.radio.config-V1-ndk",
+ "android.hardware.radio.config-V2-ndk",
"android.hardware.radio.config@1.0",
"android.hardware.radio.config@1.1",
"android.hardware.radio.config@1.2",
"android.hardware.radio.config@1.3",
- "android.hardware.radio.data-V1-ndk",
- "android.hardware.radio.messaging-V1-ndk",
- "android.hardware.radio.modem-V1-ndk",
+ "android.hardware.radio.data-V2-ndk",
+ "android.hardware.radio.ims-V1-ndk",
+ "android.hardware.radio.messaging-V2-ndk",
+ "android.hardware.radio.modem-V2-ndk",
"android.hardware.radio.network-V2-ndk",
- "android.hardware.radio.sim-V1-ndk",
- "android.hardware.radio.voice-V1-ndk",
+ "android.hardware.radio.sim-V2-ndk",
+ "android.hardware.radio.voice-V2-ndk",
"android.hardware.radio@1.0",
"android.hardware.radio@1.1",
"android.hardware.radio@1.2",
@@ -69,6 +70,9 @@
"data/RadioResponse-data.cpp",
"data/RadioData.cpp",
"data/structs.cpp",
+ "ims/RadioIndication-ims.cpp",
+ "ims/RadioResponse-ims.cpp",
+ "ims/RadioIms.cpp",
"messaging/RadioIndication-messaging.cpp",
"messaging/RadioMessaging.cpp",
"messaging/RadioResponse-messaging.cpp",
diff --git a/radio/aidl/compat/libradiocompat/ims/RadioIms.cpp b/radio/aidl/compat/libradiocompat/ims/RadioIms.cpp
new file mode 100644
index 0000000..d2bdfff
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/ims/RadioIms.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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 <libradiocompat/RadioIms.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "Ims"
+
+namespace android::hardware::radio::compat {
+
+using ::ndk::ScopedAStatus;
+namespace aidl = ::aidl::android::hardware::radio::ims;
+constexpr auto ok = &ScopedAStatus::ok;
+
+std::shared_ptr<aidl::IRadioImsResponse> RadioIms::respond() {
+ return mCallbackManager->response().imsCb();
+}
+
+ScopedAStatus RadioIms::setSrvccCallInfo(
+ int32_t serial, const std::vector<aidl::SrvccCall>& /*srvccCalls*/) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " setSrvccCallInfo is unsupported by HIDL HALs";
+ return ok();
+}
+ScopedAStatus RadioIms::updateImsRegistrationInfo(
+ int32_t serial, const aidl::ImsRegistration& /*imsRegistration*/) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " updateImsRegistrationInfo is unsupported by HIDL HALs";
+ return ok();
+}
+ScopedAStatus RadioIms::startImsTraffic(
+ int32_t serial, int32_t /*token*/, aidl::ImsTrafficType /*imsTrafficType*/,
+ ::aidl::android::hardware::radio::AccessNetwork /*accessNetworkType*/,
+ ::aidl::android::hardware::radio::ims::ImsCall::Direction /*trafficDirection*/) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " startImsTraffic is unsupported by HIDL HALs";
+ return ok();
+}
+ScopedAStatus RadioIms::stopImsTraffic(int32_t serial, int32_t /*token*/) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " stopImsTraffic is unsupported by HIDL HALs";
+ return ok();
+}
+ScopedAStatus RadioIms::triggerEpsFallback(int32_t serial, aidl::EpsFallbackReason /*reason*/) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " triggerEpsFallback is unsupported by HIDL HALs";
+ return ok();
+}
+ScopedAStatus RadioIms::sendAnbrQuery(
+ int32_t serial, aidl::ImsStreamType /*mediaType*/, aidl::ImsStreamDirection /*direction*/,
+ int32_t /*bitsPerSecond*/) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " sendAnbrQuery is unsupported by HIDL HALs";
+ return ok();
+}
+ScopedAStatus RadioIms::updateImsCallStatus(
+ int32_t serial, const std::vector<aidl::ImsCall>& /*imsCalls*/) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " updateImsCallStatus is unsupported by HIDL HALs";
+ return ok();
+}
+
+ScopedAStatus RadioIms::setResponseFunctions(
+ const std::shared_ptr<aidl::IRadioImsResponse>& response,
+ const std::shared_ptr<aidl::IRadioImsIndication>& indication) {
+ LOG_CALL << response << ' ' << indication;
+ mCallbackManager->setResponseFunctions(response, indication);
+ return ok();
+}
+
+} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/ims/RadioIndication-ims.cpp b/radio/aidl/compat/libradiocompat/ims/RadioIndication-ims.cpp
new file mode 100644
index 0000000..10109b8
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/ims/RadioIndication-ims.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 <libradiocompat/RadioIndication.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "ImsIndication"
+
+namespace android::hardware::radio::compat {
+
+using ::aidl::android::hardware::radio::RadioTechnology;
+namespace aidl = ::aidl::android::hardware::radio::ims;
+
+void RadioIndication::setResponseFunction(std::shared_ptr<aidl::IRadioImsIndication> imsCb) {
+ mImsCb = imsCb;
+}
+
+std::shared_ptr<aidl::IRadioImsIndication> RadioIndication::imsCb() {
+ return mImsCb.get();
+}
+
+} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/ims/RadioResponse-ims.cpp b/radio/aidl/compat/libradiocompat/ims/RadioResponse-ims.cpp
new file mode 100644
index 0000000..831a0ae
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/ims/RadioResponse-ims.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 <libradiocompat/RadioResponse.h>
+
+#include "commonStructs.h"
+#include "debug.h"
+
+#include "collections.h"
+
+#define RADIO_MODULE "ImsResponse"
+
+namespace android::hardware::radio::compat {
+
+namespace aidl = ::aidl::android::hardware::radio::ims;
+
+void RadioResponse::setResponseFunction(std::shared_ptr<aidl::IRadioImsResponse> imsCb) {
+ mImsCb = imsCb;
+}
+
+std::shared_ptr<aidl::IRadioImsResponse> RadioResponse::imsCb() {
+ return mImsCb.get();
+}
+
+} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIms.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIms.h
new file mode 100644
index 0000000..0dbc565
--- /dev/null
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIms.h
@@ -0,0 +1,62 @@
+/*
+ * 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 "RadioCompatBase.h"
+
+#include <aidl/android/hardware/radio/ims/BnRadioIms.h>
+
+namespace android::hardware::radio::compat {
+
+class RadioIms : public RadioCompatBase, public aidl::android::hardware::radio::ims::BnRadioIms {
+ ::ndk::ScopedAStatus setSrvccCallInfo(
+ int32_t serial,
+ const std::vector<::aidl::android::hardware::radio::ims::SrvccCall>& srvccCalls)
+ override;
+ ::ndk::ScopedAStatus updateImsRegistrationInfo(
+ int32_t serial,
+ const ::aidl::android::hardware::radio::ims::ImsRegistration& imsRegistration) override;
+ ::ndk::ScopedAStatus startImsTraffic(
+ int32_t serial, int32_t token,
+ ::aidl::android::hardware::radio::ims::ImsTrafficType imsTrafficType,
+ ::aidl::android::hardware::radio::AccessNetwork accessNetworkType,
+ ::aidl::android::hardware::radio::ims::ImsCall::Direction trafficDirection) override;
+ ::ndk::ScopedAStatus stopImsTraffic(int32_t serial, int32_t token) override;
+ ::ndk::ScopedAStatus triggerEpsFallback(
+ int32_t serial,
+ ::aidl::android::hardware::radio::ims::EpsFallbackReason reason) override;
+ ::ndk::ScopedAStatus sendAnbrQuery(
+ int32_t serial, ::aidl::android::hardware::radio::ims::ImsStreamType mediaType,
+ ::aidl::android::hardware::radio::ims::ImsStreamDirection direction,
+ int32_t bitsPerSecond) override;
+ ::ndk::ScopedAStatus updateImsCallStatus(
+ int32_t serial,
+ const std::vector<::aidl::android::hardware::radio::ims::ImsCall>& imsCalls) override;
+
+ ::ndk::ScopedAStatus setResponseFunctions(
+ const std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsResponse>&
+ radioImsResponse,
+ const std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsIndication>&
+ radioImsIndication) override;
+
+ protected:
+ std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsResponse> respond();
+
+ public:
+ using RadioCompatBase::RadioCompatBase;
+};
+
+} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
index 6cfd59c..f042456 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioIndication.h
@@ -19,6 +19,7 @@
#include "GuaranteedCallback.h"
#include <aidl/android/hardware/radio/data/IRadioDataIndication.h>
+#include <aidl/android/hardware/radio/ims/IRadioImsIndication.h>
#include <aidl/android/hardware/radio/messaging/IRadioMessagingIndication.h>
#include <aidl/android/hardware/radio/modem/IRadioModemIndication.h>
#include <aidl/android/hardware/radio/network/IRadioNetworkIndication.h>
@@ -55,6 +56,10 @@
::aidl::android::hardware::radio::voice::IRadioVoiceIndication,
::aidl::android::hardware::radio::voice::IRadioVoiceIndicationDefault, true>
mVoiceCb;
+ GuaranteedCallback< //
+ ::aidl::android::hardware::radio::ims::IRadioImsIndication,
+ ::aidl::android::hardware::radio::ims::IRadioImsIndicationDefault, true>
+ mImsCb;
// IRadioIndication @ 1.0
Return<void> radioStateChanged(V1_0::RadioIndicationType type,
@@ -220,6 +225,8 @@
std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimIndication> simCb);
void setResponseFunction(
std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceIndication> voicCb);
+ void setResponseFunction(
+ std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsIndication> imsCb);
std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataIndication> dataCb();
std::shared_ptr<::aidl::android::hardware::radio::messaging::IRadioMessagingIndication>
@@ -228,6 +235,7 @@
std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkIndication> networkCb();
std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimIndication> simCb();
std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceIndication> voiceCb();
+ std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsIndication> imsCb();
};
} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
index 5dd6f0a..f9f3c6c 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
@@ -99,6 +99,10 @@
scanTrigger) override;
::ndk::ScopedAStatus cancelEmergencyNetworkScan(int32_t serial, bool resetScan) override;
::ndk::ScopedAStatus exitEmergencyMode(int32_t serial) override;
+ ::ndk::ScopedAStatus isN1ModeEnabled(int32_t serial) override;
+ ::ndk::ScopedAStatus setN1ModeEnabled(int32_t serial, bool enable) override;
+
+ ::ndk::ScopedAStatus setNullCipherAndIntegrityEnabled(int32_t serial, bool enabled) override;
protected:
std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> respond();
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h
index 1f82dd1..22451ae 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioResponse.h
@@ -19,6 +19,7 @@
#include "GuaranteedCallback.h"
#include <aidl/android/hardware/radio/data/IRadioDataResponse.h>
+#include <aidl/android/hardware/radio/ims/IRadioImsResponse.h>
#include <aidl/android/hardware/radio/messaging/IRadioMessagingResponse.h>
#include <aidl/android/hardware/radio/modem/IRadioModemResponse.h>
#include <aidl/android/hardware/radio/network/IRadioNetworkResponse.h>
@@ -49,6 +50,9 @@
GuaranteedCallback<::aidl::android::hardware::radio::voice::IRadioVoiceResponse,
::aidl::android::hardware::radio::voice::IRadioVoiceResponseDefault>
mVoiceCb;
+ GuaranteedCallback<::aidl::android::hardware::radio::ims::IRadioImsResponse,
+ ::aidl::android::hardware::radio::ims::IRadioImsResponseDefault>
+ mImsCb;
// IRadioResponse @ 1.0
Return<void> getIccCardStatusResponse(const V1_0::RadioResponseInfo& info,
@@ -440,6 +444,8 @@
std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimResponse> simCb);
void setResponseFunction(
std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceResponse> voiceCb);
+ void setResponseFunction(
+ std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsResponse> imsCb);
std::shared_ptr<::aidl::android::hardware::radio::data::IRadioDataResponse> dataCb();
std::shared_ptr<::aidl::android::hardware::radio::messaging::IRadioMessagingResponse>
@@ -448,6 +454,7 @@
std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> networkCb();
std::shared_ptr<::aidl::android::hardware::radio::sim::IRadioSimResponse> simCb();
std::shared_ptr<::aidl::android::hardware::radio::voice::IRadioVoiceResponse> voiceCb();
+ std::shared_ptr<::aidl::android::hardware::radio::ims::IRadioImsResponse> imsCb();
};
} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index 6bb6b75..005deae 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -340,4 +340,24 @@
return ok();
}
+ScopedAStatus RadioNetwork::setNullCipherAndIntegrityEnabled(int32_t serial, bool) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " setNullCipherAndIntegrityEnabled is unsupported by HIDL HALs";
+ respond()->setNullCipherAndIntegrityEnabledResponse(notSupported(serial));
+ return ok();
+}
+
+ScopedAStatus RadioNetwork::isN1ModeEnabled(int32_t serial) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " isN1ModeEnabled is unsupported by HIDL HALs";
+ respond()->isN1ModeEnabledResponse(notSupported(serial), false);
+ return ok();
+}
+
+ScopedAStatus RadioNetwork::setN1ModeEnabled(int32_t serial, bool /*enable*/) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " setN1ModeEnabled is unsupported by HIDL HALs";
+ respond()->setN1ModeEnabledResponse(notSupported(serial));
+ return ok();
+}
} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/compat/service/Android.bp b/radio/aidl/compat/service/Android.bp
index 4dbaef4..7a48da2 100644
--- a/radio/aidl/compat/service/Android.bp
+++ b/radio/aidl/compat/service/Android.bp
@@ -34,17 +34,18 @@
],
shared_libs: [
"android.hardware.radio-library.compat",
- "android.hardware.radio.config-V1-ndk",
+ "android.hardware.radio.config-V2-ndk",
"android.hardware.radio.config@1.0",
"android.hardware.radio.config@1.1",
"android.hardware.radio.config@1.2",
"android.hardware.radio.config@1.3",
- "android.hardware.radio.data-V1-ndk",
- "android.hardware.radio.messaging-V1-ndk",
- "android.hardware.radio.modem-V1-ndk",
+ "android.hardware.radio.data-V2-ndk",
+ "android.hardware.radio.ims-V1-ndk",
+ "android.hardware.radio.messaging-V2-ndk",
+ "android.hardware.radio.modem-V2-ndk",
"android.hardware.radio.network-V2-ndk",
- "android.hardware.radio.sim-V1-ndk",
- "android.hardware.radio.voice-V1-ndk",
+ "android.hardware.radio.sim-V2-ndk",
+ "android.hardware.radio.voice-V2-ndk",
"android.hardware.radio@1.0",
"android.hardware.radio@1.1",
"android.hardware.radio@1.2",
diff --git a/radio/aidl/vts/Android.bp b/radio/aidl/vts/Android.bp
index bb992c9..5a0dbd0 100644
--- a/radio/aidl/vts/Android.bp
+++ b/radio/aidl/vts/Android.bp
@@ -66,15 +66,15 @@
"libvintf",
],
static_libs: [
- "android.hardware.radio-V1-ndk",
- "android.hardware.radio.config-V1-ndk",
- "android.hardware.radio.data-V1-ndk",
+ "android.hardware.radio-V2-ndk",
+ "android.hardware.radio.config-V2-ndk",
+ "android.hardware.radio.data-V2-ndk",
"android.hardware.radio.ims-V1-ndk",
- "android.hardware.radio.messaging-V1-ndk",
- "android.hardware.radio.modem-V1-ndk",
+ "android.hardware.radio.messaging-V2-ndk",
+ "android.hardware.radio.modem-V2-ndk",
"android.hardware.radio.network-V2-ndk",
- "android.hardware.radio.sim-V1-ndk",
- "android.hardware.radio.voice-V1-ndk",
+ "android.hardware.radio.sim-V2-ndk",
+ "android.hardware.radio.voice-V2-ndk",
],
test_suites: [
"general-tests",
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.cpp b/radio/aidl/vts/radio_aidl_hal_utils.cpp
index efc4f26..6ed8e7d 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.cpp
+++ b/radio/aidl/vts/radio_aidl_hal_utils.cpp
@@ -92,6 +92,10 @@
return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsds");
}
+bool isDsDaEnabled() {
+ return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "dsda");
+}
+
bool isTsTsEnabled() {
return testing::checkSubstringInCommandOutput("getprop persist.radio.multisim.config", "tsts");
}
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.h b/radio/aidl/vts/radio_aidl_hal_utils.h
index 4ed6b3f..d515e1a 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.h
+++ b/radio/aidl/vts/radio_aidl_hal_utils.h
@@ -106,6 +106,11 @@
bool isDsDsEnabled();
/*
+ * Check if device is in DSDA (Dual SIM Dual Active).
+ */
+bool isDsDaEnabled();
+
+/*
* Check if device is in TSTS (Triple SIM Triple Standby).
*/
bool isTsTsEnabled();
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index 258b172..c979d28 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -176,7 +176,7 @@
slotPortMapping.physicalSlotId = -1;
slotPortMapping.portId = -1;
std::vector<SlotPortMapping> slotPortMappingList = {slotPortMapping};
- if (isDsDsEnabled()) {
+ if (isDsDsEnabled() || isDsDaEnabled()) {
slotPortMappingList.push_back(slotPortMapping);
} else if (isTsTsEnabled()) {
slotPortMappingList.push_back(slotPortMapping);
@@ -252,7 +252,7 @@
}
if (isSsSsEnabled()) {
EXPECT_EQ(1, simCount);
- } else if (isDsDsEnabled()) {
+ } else if (isDsDsEnabled() || isDsDaEnabled()) {
EXPECT_EQ(2, simCount);
} else if (isTsTsEnabled()) {
EXPECT_EQ(3, simCount);
diff --git a/radio/aidl/vts/radio_ims_test.cpp b/radio/aidl/vts/radio_ims_test.cpp
index 5e3f057..289d3ed 100644
--- a/radio/aidl/vts/radio_ims_test.cpp
+++ b/radio/aidl/vts/radio_ims_test.cpp
@@ -252,7 +252,6 @@
case RadioError::MODEM_ERR:
case RadioError::INTERNAL_ERR:
case RadioError::INVALID_ARGUMENTS:
- case RadioError::REQUEST_NOT_SUPPORTED:
case RadioError::NO_RESOURCES:
SUCCEED();
break;
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
index 5599c03..c890df0 100644
--- a/radio/aidl/vts/radio_network_response.cpp
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -293,3 +293,23 @@
parent_network.notify(info.serial);
return ndk::ScopedAStatus::ok();
}
+
+ndk::ScopedAStatus RadioNetworkResponse::setNullCipherAndIntegrityEnabledResponse(
+ const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_network.notify(info.serial);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::isN1ModeEnabledResponse(
+ const RadioResponseInfo& info, bool /*isEnabled*/) {
+ rspInfo = info;
+ parent_network.notify(info.serial);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus RadioNetworkResponse::setN1ModeEnabledResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_network.notify(info.serial);
+ return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 31f4aca..5872eb0 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -1501,7 +1501,7 @@
RadioTechnology rat = radioRsp_network->dataRegResp.rat;
// TODO: add logic for cdmaInfo
- if (rat == RadioTechnology::LTE || rat == RadioTechnology::LTE_CA) {
+ if (rat == RadioTechnology::LTE) {
ASSERT_EQ(info.getTag(), AccessTechnologySpecificInfo::eutranInfo);
} else if (rat == RadioTechnology::NR) {
ASSERT_TRUE(info.getTag() == AccessTechnologySpecificInfo::ngranNrVopsInfo);
@@ -1914,3 +1914,50 @@
RadioError::MODEM_ERR}));
LOG(DEBUG) << "exitEmergencyMode finished";
}
+
+/*
+ * Test IRadioNetwork.setN1ModeEnabled() for the response returned.
+ */
+TEST_P(RadioNetworkTest, setN1ModeEnabled) {
+ serial = GetRandomSerialNumber();
+
+ ndk::ScopedAStatus res =
+ radio_network->setN1ModeEnabled(serial, false);
+ ASSERT_OK(res);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+ if (getRadioHalCapabilities()) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::REQUEST_NOT_SUPPORTED}));
+ } else {
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR,
+ RadioError::INVALID_STATE, RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+ }
+}
+
+/*
+ * Test IRadioNetwork.isN1ModeEnabled() for the response returned.
+ */
+TEST_P(RadioNetworkTest, isN1ModeEnabled) {
+ serial = GetRandomSerialNumber();
+
+ ndk::ScopedAStatus res = radio_network->isN1ModeEnabled(serial);
+ ASSERT_OK(res);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+ if (getRadioHalCapabilities()) {
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::REQUEST_NOT_SUPPORTED}));
+ } else {
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::RADIO_NOT_AVAILABLE, RadioError::INTERNAL_ERR,
+ RadioError::REQUEST_NOT_SUPPORTED, RadioError::NONE}));
+ }
+}
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
index 8480825..e6a320b 100644
--- a/radio/aidl/vts/radio_network_utils.h
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -158,6 +158,14 @@
virtual ndk::ScopedAStatus cancelEmergencyNetworkScanResponse(
const RadioResponseInfo& info) override;
+
+ virtual ndk::ScopedAStatus setNullCipherAndIntegrityEnabledResponse(
+ const RadioResponseInfo& info) override;
+
+ virtual ndk::ScopedAStatus isN1ModeEnabledResponse(
+ const RadioResponseInfo& info, bool isEnabled) override;
+
+ virtual ndk::ScopedAStatus setN1ModeEnabledResponse(const RadioResponseInfo& info) override;
};
/* Callback class for radio network indication */
diff --git a/security/keymint/README.md b/security/keymint/README.md
new file mode 100644
index 0000000..54647af
--- /dev/null
+++ b/security/keymint/README.md
@@ -0,0 +1,10 @@
+# KeyMint HAL
+
+This directory contains the HAL definition for KeyMint. KeyMint provides
+cryptographic services in a hardware-isolated environment.
+
+Note that the `IRemotelyProvisionedComponent` HAL, and it's associated types,
+used to also be defined in this directory. As of Android U, this HAL has been
+moved to a different directory (../rkp). This move is ABI compatible, as the
+interfaces have been maintained. The build is split so that the generated
+code may be built with different options.
diff --git a/security/keymint/TEST_MAPPING b/security/keymint/TEST_MAPPING
index 9ce5e9b..4ab60b6 100644
--- a/security/keymint/TEST_MAPPING
+++ b/security/keymint/TEST_MAPPING
@@ -1,6 +1,9 @@
{
"presubmit": [
{
+ "name": "VtsAidlKeyMintTargetTest"
+ },
+ {
"name": "VtsHalRemotelyProvisionedComponentTargetTest"
}
]
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
index b712a52..3a6d415 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/.hash
@@ -1 +1,2 @@
976674616001f714f4a4df49ee45f548de828524
+cd862ae2e49b54fc965dc1b99c218eb729c93bb1
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
index 69ba9a6..b4c2b78 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/.hash
@@ -1 +1,2 @@
207c9f218b9b9e4e74ff5232eb16511eca9d7d2e
+70c734fbd5cac5b36676d66d8d9aa941967e1e7b
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
index e310b44..6ae2369 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/Tag.aidl
@@ -90,6 +90,7 @@
DEVICE_UNIQUE_ATTESTATION = 1879048912,
IDENTITY_CREDENTIAL_KEY = 1879048913,
STORAGE_KEY = 1879048914,
+ ATTESTATION_ID_SECOND_IMEI = -1879047469,
ASSOCIATED_DATA = -1879047192,
NONCE = -1879047191,
MAC_LENGTH = 805307371,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index 47361d5..837fc81 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -726,9 +726,10 @@
ATTESTATION_ID_SERIAL = TagType.BYTES | 713,
/**
- * Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attested key
+ * Tag::ATTESTATION_ID_IMEI provides the IMEI one of the radios on the device to attested key
* generation/import operations. This field must be set only when requesting attestation of the
- * device's identifiers.
+ * device's identifiers. If the device has more than one IMEI, a second IMEI may be included
+ * by using the Tag::ATTESTATION_ID_SECOND_IMEI tag.
*
* If the device does not support ID attestation (or destroyAttestationIds() was previously
* called and the device can no longer attest its IDs), any key attestation request that
@@ -883,6 +884,20 @@
STORAGE_KEY = TagType.BOOL | 722,
/**
+ * Tag::ATTESTATION_ID_SECOND_IMEI provides an additional IMEI of one of the radios on the
+ * device to attested key generation/import operations. This field MUST be accompanied by
+ * the Tag::ATTESTATION_ID_IMEI tag. It would only be used to convery a second IMEI the device
+ * has, after Tag::ATTESTATION_ID_SECOND_IMEI has been used to convery the first IMEI.
+ *
+ * If the device does not support ID attestation (or destroyAttestationIds() was previously
+ * called and the device can no longer attest its IDs), any key attestation request that
+ * includes this tag must fail with ErrorCode::CANNOT_ATTEST_IDS.
+ *
+ * Must never appear in KeyCharacteristics.
+ */
+ ATTESTATION_ID_SECOND_IMEI = TagType.BYTES | 723,
+
+ /**
* OBSOLETE: Do not use.
*
* This tag value is included for historical reasons -- in Keymaster it was used to hold
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index 1a17fd4..17520b7 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -25,6 +25,7 @@
"keymint_use_latest_hal_aidl_ndk_shared",
],
shared_libs: [
+ "android.hardware.security.rkp-V3-ndk",
"android.hardware.security.sharedsecret-V1-ndk",
"android.hardware.security.secureclock-V1-ndk",
"libbase",
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index ef5b0bd..13143bf 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -35,6 +35,7 @@
"libcrypto",
],
static_libs: [
+ "android.hardware.security.rkp-V3-ndk",
"android.hardware.security.secureclock-V1-ndk",
"libcppbor_external",
"libcppcose_rkp",
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index ca517ac..f4c0095 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -798,7 +798,7 @@
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
"ro.product.manufacturer");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index 1dc5df3..cd140c8 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -252,7 +252,7 @@
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+ add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
"ro.product.manufacturer");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 5473062..80abd92 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -1919,30 +1919,32 @@
// The following check assumes that canonical CBOR encoding is used for the COSE_Key.
if (testMode) {
- EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
- MatchesRegex("{\n"
- " 1 : 2,\n" // kty: EC2
- " 3 : -7,\n" // alg: ES256
- " -1 : 1,\n" // EC id: P256
- // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
- // sequence of 32 hexadecimal bytes, enclosed in braces and
- // separated by commas. In this case, some Ed25519 public key.
- " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
- " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
- " -70000 : null,\n" // test marker
- "}"));
+ EXPECT_THAT(
+ cppbor::prettyPrint(parsedPayload.get()),
+ MatchesRegex("\\{\n"
+ " 1 : 2,\n" // kty: EC2
+ " 3 : -7,\n" // alg: ES256
+ " -1 : 1,\n" // EC id: P256
+ // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+ // sequence of 32 hexadecimal bytes, enclosed in braces and
+ // separated by commas. In this case, some Ed25519 public key.
+ " -2 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n" // pub_x: data
+ " -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n" // pub_y: data
+ " -70000 : null,\n" // test marker
+ "\\}"));
} else {
- EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
- MatchesRegex("{\n"
- " 1 : 2,\n" // kty: EC2
- " 3 : -7,\n" // alg: ES256
- " -1 : 1,\n" // EC id: P256
- // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
- // sequence of 32 hexadecimal bytes, enclosed in braces and
- // separated by commas. In this case, some Ed25519 public key.
- " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
- " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
- "}"));
+ EXPECT_THAT(
+ cppbor::prettyPrint(parsedPayload.get()),
+ MatchesRegex("\\{\n"
+ " 1 : 2,\n" // kty: EC2
+ " 3 : -7,\n" // alg: ES256
+ " -1 : 1,\n" // EC id: P256
+ // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+ // sequence of 32 hexadecimal bytes, enclosed in braces and
+ // separated by commas. In this case, some Ed25519 public key.
+ " -2 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n" // pub_x: data
+ " -3 : \\{(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}\\},\n" // pub_y: data
+ "\\}"));
}
}
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 2194529..b8d0c20 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1027,6 +1027,15 @@
* without providing NOT_BEFORE and NOT_AFTER parameters.
*/
TEST_P(NewKeyGenerationTest, RsaWithMissingValidity) {
+ if (AidlVersion() < 2) {
+ /*
+ * The KeyMint V1 spec required that CERTIFICATE_NOT_{BEFORE,AFTER} be
+ * specified for asymmetric key generation. However, this was not
+ * checked at the time so we can only be strict about checking this for
+ * implementations of KeyMint version 2 and above.
+ */
+ GTEST_SKIP() << "Validity strict since KeyMint v2";
+ }
// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to
// GeneralizedTime 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
constexpr uint64_t kUndefinedExpirationDateTime = 253402300799000;
@@ -1680,6 +1689,15 @@
* without providing NOT_BEFORE and NOT_AFTER parameters.
*/
TEST_P(NewKeyGenerationTest, EcdsaWithMissingValidity) {
+ if (AidlVersion() < 2) {
+ /*
+ * The KeyMint V1 spec required that CERTIFICATE_NOT_{BEFORE,AFTER} be
+ * specified for asymmetric key generation. However, this was not
+ * checked at the time so we can only be strict about checking this for
+ * implementations of KeyMint version 2 and above.
+ */
+ GTEST_SKIP() << "Validity strict since KeyMint v2";
+ }
// Per RFC 5280 4.1.2.5, an undefined expiration (not-after) field should be set to
// GeneralizedTime 999912312359559, which is 253402300799000 ms from Jan 1, 1970.
constexpr uint64_t kUndefinedExpirationDateTime = 253402300799000;
@@ -1990,7 +2008,7 @@
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
- add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+ add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "ro.product.manufacturer");
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 4f361bb..97fe08a 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -251,6 +251,19 @@
EXPECT_LE(hwInfo.uniqueId->size(), 32);
}
+/**
+ * Verify implementation supports at least MIN_SUPPORTED_NUM_KEYS_IN_CSR keys in a CSR.
+ */
+TEST_P(GetHardwareInfoTests, supportedNumKeysInCsr) {
+ if (rpcHardwareInfo.versionNumber < VERSION_WITHOUT_TEST_MODE) {
+ return;
+ }
+
+ RpcHardwareInfo hwInfo;
+ ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
+ ASSERT_GE(hwInfo.supportedNumKeysInCsr, RpcHardwareInfo::MIN_SUPPORTED_NUM_KEYS_IN_CSR);
+}
+
using GenerateKeyTests = VtsRemotelyProvisionedComponentTests;
INSTANTIATE_REM_PROV_AIDL_TEST(GenerateKeyTests);
@@ -701,7 +714,8 @@
}
/**
- * Generate a non-empty certificate request. Make sure contents are reproducible.
+ * Generate a non-empty certificate request. Make sure contents are reproducible but allow for the
+ * signature to be different since algorithms including ECDSA P-256 can include a random value.
*/
TEST_P(CertificateRequestV2Test, NonEmptyRequestReproducible) {
generateKeys(false /* testMode */, 1 /* numKeys */);
@@ -711,27 +725,23 @@
auto status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
ASSERT_TRUE(status.isOk()) << status.getMessage();
- auto firstBcc = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
- ASSERT_TRUE(firstBcc) << firstBcc.message();
+ auto firstCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+ ASSERT_TRUE(firstCsr) << firstCsr.message();
status = provisionable_->generateCertificateRequestV2(keysToSign_, challenge_, &csr);
ASSERT_TRUE(status.isOk()) << status.getMessage();
- auto secondBcc = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
- ASSERT_TRUE(secondBcc) << secondBcc.message();
+ auto secondCsr = verifyProductionCsr(cborKeysToSign_, csr, provisionable_.get(), challenge_);
+ ASSERT_TRUE(secondCsr) << secondCsr.message();
- ASSERT_EQ(firstBcc->size(), secondBcc->size());
- for (auto i = 0; i < firstBcc->size(); i++) {
- ASSERT_EQ(firstBcc->at(i).pubKey, secondBcc->at(i).pubKey);
- }
+ ASSERT_EQ(**firstCsr, **secondCsr);
}
/**
* Generate a non-empty certificate request with multiple keys.
*/
TEST_P(CertificateRequestV2Test, NonEmptyRequestMultipleKeys) {
- // TODO(b/254137722): define a minimum number of keys that must be supported.
- generateKeys(false /* testMode */, 5 /* numKeys */);
+ generateKeys(false /* testMode */, rpcHardwareInfo.supportedNumKeysInCsr /* numKeys */);
bytevec csr;
diff --git a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
index 5bbae4c..0c61c25 100644
--- a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
+++ b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
@@ -16,16 +16,21 @@
#define LOG_TAG "keymint_benchmark"
+#include <iostream>
+
#include <base/command_line.h>
#include <benchmark/benchmark.h>
-#include <iostream>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
#include <android/binder_manager.h>
#include <binder/IServiceManager.h>
+
#include <keymint_support/authorization_set.h>
+#include <keymint_support/openssl_utils.h>
+#include <openssl/curve25519.h>
+#include <openssl/x509.h>
#define SMALL_MESSAGE_SIZE 64
#define MEDIUM_MESSAGE_SIZE 1024
@@ -119,6 +124,22 @@
return {};
}
+ string getAlgorithmString(string transform) {
+ if (transform.find("AES") != string::npos) {
+ return "AES";
+ } else if (transform.find("Hmac") != string::npos) {
+ return "HMAC";
+ } else if (transform.find("DESede") != string::npos) {
+ return "TRIPLE_DES";
+ } else if (transform.find("RSA") != string::npos) {
+ return "RSA";
+ } else if (transform.find("EC") != string::npos) {
+ return "EC";
+ }
+ std::cerr << "Can't find algorithm for " << transform << std::endl;
+ return "";
+ }
+
Digest getDigest(string transform) {
if (transform.find("MD5") != string::npos) {
return Digest::MD5;
@@ -135,29 +156,56 @@
return Digest::SHA_2_512;
} else if (transform.find("RSA") != string::npos &&
transform.find("OAEP") != string::npos) {
- return Digest::SHA1;
+ if (securityLevel_ == SecurityLevel::STRONGBOX) {
+ return Digest::SHA_2_256;
+ } else {
+ return Digest::SHA1;
+ }
} else if (transform.find("Hmac") != string::npos) {
return Digest::SHA_2_256;
}
return Digest::NONE;
}
+ string getDigestString(string transform) {
+ if (transform.find("MD5") != string::npos) {
+ return "MD5";
+ } else if (transform.find("SHA1") != string::npos ||
+ transform.find("SHA-1") != string::npos) {
+ return "SHA1";
+ } else if (transform.find("SHA224") != string::npos) {
+ return "SHA_2_224";
+ } else if (transform.find("SHA256") != string::npos) {
+ return "SHA_2_256";
+ } else if (transform.find("SHA384") != string::npos) {
+ return "SHA_2_384";
+ } else if (transform.find("SHA512") != string::npos) {
+ return "SHA_2_512";
+ } else if (transform.find("RSA") != string::npos &&
+ transform.find("OAEP") != string::npos) {
+ if (securityLevel_ == SecurityLevel::STRONGBOX) {
+ return "SHA_2_256";
+ } else {
+ return "SHA1";
+ }
+ } else if (transform.find("Hmac") != string::npos) {
+ return "SHA_2_256";
+ }
+ return "";
+ }
+
optional<EcCurve> getCurveFromLength(int keySize) {
switch (keySize) {
case 224:
return EcCurve::P_224;
- break;
case 256:
return EcCurve::P_256;
- break;
case 384:
return EcCurve::P_384;
- break;
case 521:
return EcCurve::P_521;
- break;
default:
- return {};
+ return std::nullopt;
}
}
@@ -261,6 +309,109 @@
return GetReturnErrorCode(result);
}
+ /* Copied the function LocalRsaEncryptMessage from
+ * hardware/interfaces/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp in VTS.
+ * Replaced asserts with the condition check and return false in case of failure condition.
+ * Require return value to skip the benchmark test case from further execution in case
+ * LocalRsaEncryptMessage fails.
+ */
+ optional<string> LocalRsaEncryptMessage(const string& message, const AuthorizationSet& params) {
+ // Retrieve the public key from the leaf certificate.
+ if (cert_chain_.empty()) {
+ std::cerr << "Local RSA encrypt Error: invalid cert_chain_" << std::endl;
+ return "Failure";
+ }
+ X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ EVP_PKEY_Ptr pub_key(X509_get_pubkey(key_cert.get()));
+ RSA_Ptr rsa(EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(pub_key.get())));
+
+ // Retrieve relevant tags.
+ Digest digest = Digest::NONE;
+ Digest mgf_digest = Digest::SHA1;
+ PaddingMode padding = PaddingMode::NONE;
+
+ auto digest_tag = params.GetTagValue(TAG_DIGEST);
+ if (digest_tag.has_value()) digest = digest_tag.value();
+ auto pad_tag = params.GetTagValue(TAG_PADDING);
+ if (pad_tag.has_value()) padding = pad_tag.value();
+ auto mgf_tag = params.GetTagValue(TAG_RSA_OAEP_MGF_DIGEST);
+ if (mgf_tag.has_value()) mgf_digest = mgf_tag.value();
+
+ const EVP_MD* md = openssl_digest(digest);
+ const EVP_MD* mgf_md = openssl_digest(mgf_digest);
+
+ // Set up encryption context.
+ EVP_PKEY_CTX_Ptr ctx(EVP_PKEY_CTX_new(pub_key.get(), /* engine= */ nullptr));
+ if (EVP_PKEY_encrypt_init(ctx.get()) <= 0) {
+ std::cerr << "Local RSA encrypt Error: Encryption init failed" << std::endl;
+ return "Failure";
+ }
+
+ int rc = -1;
+ switch (padding) {
+ case PaddingMode::NONE:
+ rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
+ break;
+ case PaddingMode::RSA_PKCS1_1_5_ENCRYPT:
+ rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PADDING);
+ break;
+ case PaddingMode::RSA_OAEP:
+ rc = EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING);
+ break;
+ default:
+ break;
+ }
+ if (rc <= 0) {
+ std::cerr << "Local RSA encrypt Error: Set padding failed" << std::endl;
+ return "Failure";
+ }
+ if (padding == PaddingMode::RSA_OAEP) {
+ if (!EVP_PKEY_CTX_set_rsa_oaep_md(ctx.get(), md)) {
+ std::cerr << "Local RSA encrypt Error: Set digest failed: " << ERR_peek_last_error()
+ << std::endl;
+ return "Failure";
+ }
+ if (!EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), mgf_md)) {
+ std::cerr << "Local RSA encrypt Error: Set digest failed: " << ERR_peek_last_error()
+ << std::endl;
+ return "Failure";
+ }
+ }
+
+ // Determine output size.
+ size_t outlen;
+ if (EVP_PKEY_encrypt(ctx.get(), nullptr /* out */, &outlen,
+ reinterpret_cast<const uint8_t*>(message.data()),
+ message.size()) <= 0) {
+ std::cerr << "Local RSA encrypt Error: Determine output size failed: "
+ << ERR_peek_last_error() << std::endl;
+ return "Failure";
+ }
+
+ // Left-zero-pad the input if necessary.
+ const uint8_t* to_encrypt = reinterpret_cast<const uint8_t*>(message.data());
+ size_t to_encrypt_len = message.size();
+
+ std::unique_ptr<string> zero_padded_message;
+ if (padding == PaddingMode::NONE && to_encrypt_len < outlen) {
+ zero_padded_message.reset(new string(outlen, '\0'));
+ memcpy(zero_padded_message->data() + (outlen - to_encrypt_len), message.data(),
+ message.size());
+ to_encrypt = reinterpret_cast<const uint8_t*>(zero_padded_message->data());
+ to_encrypt_len = outlen;
+ }
+
+ // Do the encryption.
+ string output(outlen, '\0');
+ if (EVP_PKEY_encrypt(ctx.get(), reinterpret_cast<uint8_t*>(output.data()), &outlen,
+ to_encrypt, to_encrypt_len) <= 0) {
+ std::cerr << "Local RSA encrypt Error: Encryption failed: " << ERR_peek_last_error()
+ << std::endl;
+ return "Failure";
+ }
+ return output;
+ }
+
SecurityLevel securityLevel_;
string name_;
@@ -268,12 +419,13 @@
ErrorCode GenerateKey(const AuthorizationSet& key_desc,
const optional<AttestationKey>& attest_key = std::nullopt) {
key_blob_.clear();
+ cert_chain_.clear();
KeyCreationResult creationResult;
Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
if (result.isOk()) {
key_blob_ = std::move(creationResult.keyBlob);
+ cert_chain_ = std::move(creationResult.certificateChain);
creationResult.keyCharacteristics.clear();
- creationResult.certificateChain.clear();
}
return GetReturnErrorCode(result);
}
@@ -338,6 +490,11 @@
return ErrorCode::UNKNOWN_ERROR;
}
+ X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
+ const uint8_t* p = blob.data();
+ return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
+ }
+
std::shared_ptr<IKeyMintOperation> op_;
vector<Certificate> cert_chain_;
vector<uint8_t> key_blob_;
@@ -390,6 +547,10 @@
BENCHMARK_KM_MSG(encrypt, transform, keySize, msgSize) \
BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
+// Skip public key operations as they are not supported in KeyMint.
+#define BENCHMARK_KM_ASYM_CIPHER(transform, keySize, msgSize) \
+ BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
+
#define BENCHMARK_KM_CIPHER_ALL_MSGS(transform, keySize) \
BENCHMARK_KM_ALL_MSGS(encrypt, transform, keySize) \
BENCHMARK_KM_ALL_MSGS(decrypt, transform, keySize)
@@ -397,12 +558,43 @@
#define BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, keySize) \
BENCHMARK_KM_ALL_MSGS(sign, transform, keySize) \
BENCHMARK_KM_ALL_MSGS(verify, transform, keySize)
-// clang-format on
+
+// Skip public key operations as they are not supported in KeyMint.
+#define BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, keySize) \
+ BENCHMARK_KM_ALL_MSGS(sign, transform, keySize) \
+ // clang-format on
/*
* ============= KeyGen TESTS ==================
*/
+
+static bool isValidSBKeySize(string transform, int keySize) {
+ std::optional<Algorithm> algorithm = keymintTest->getAlgorithm(transform);
+ switch (algorithm.value()) {
+ case Algorithm::AES:
+ return (keySize == 128 || keySize == 256);
+ case Algorithm::HMAC:
+ return (keySize % 8 == 0 && keySize >= 64 && keySize <= 512);
+ case Algorithm::TRIPLE_DES:
+ return (keySize == 168);
+ case Algorithm::RSA:
+ return (keySize == 2048);
+ case Algorithm::EC:
+ return (keySize == 256);
+ }
+ return false;
+}
+
static void keygen(benchmark::State& state, string transform, int keySize) {
+ // Skip the test for unsupported key size in StrongBox
+ if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+ !isValidSBKeySize(transform, keySize)) {
+ state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+ " is not supported in StrongBox for algorithm: " +
+ keymintTest->getAlgorithmString(transform))
+ .c_str());
+ return;
+ }
addDefaultLabel(state);
for (auto _ : state) {
if (!keymintTest->GenerateKey(transform, keySize)) {
@@ -438,8 +630,24 @@
/*
* ============= SIGNATURE TESTS ==================
*/
-
static void sign(benchmark::State& state, string transform, int keySize, int msgSize) {
+ // Skip the test for unsupported key size or unsupported digest in StrongBox
+ if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX) {
+ if (!isValidSBKeySize(transform, keySize)) {
+ state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+ " is not supported in StrongBox for algorithm: " +
+ keymintTest->getAlgorithmString(transform))
+ .c_str());
+ return;
+ }
+ if (keymintTest->getDigest(transform) != Digest::SHA_2_256) {
+ state.SkipWithError(
+ ("Skipped for STRONGBOX: Digest: " + keymintTest->getDigestString(transform) +
+ " is not supported in StrongBox")
+ .c_str());
+ return;
+ }
+ }
addDefaultLabel(state);
if (!keymintTest->GenerateKey(transform, keySize, true)) {
state.SkipWithError(
@@ -469,6 +677,23 @@
}
static void verify(benchmark::State& state, string transform, int keySize, int msgSize) {
+ // Skip the test for unsupported key size or unsupported digest in StrongBox
+ if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX) {
+ if (!isValidSBKeySize(transform, keySize)) {
+ state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+ " is not supported in StrongBox for algorithm: " +
+ keymintTest->getAlgorithmString(transform))
+ .c_str());
+ return;
+ }
+ if (keymintTest->getDigest(transform) != Digest::SHA_2_256) {
+ state.SkipWithError(
+ ("Skipped for STRONGBOX: Digest: " + keymintTest->getDigestString(transform) +
+ " is not supported in StrongBox")
+ .c_str());
+ return;
+ }
+ }
addDefaultLabel(state);
if (!keymintTest->GenerateKey(transform, keySize, true)) {
state.SkipWithError(
@@ -525,10 +750,10 @@
BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA512)
#define BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(transform) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 224) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 256) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 384) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 521)
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 224) \
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 256) \
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 384) \
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 521)
BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(NONEwithECDSA);
BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA1withECDSA);
@@ -538,13 +763,14 @@
BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA512withECDSA);
#define BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(transform) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 2048) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 3072) \
- BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 4096)
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 2048) \
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 3072) \
+ BENCHMARK_KM_ASYM_SIGNATURE_ALL_MSGS(transform, 4096)
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(MD5withRSA);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA1withRSA);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA256withRSA);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA);
@@ -553,6 +779,7 @@
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA/PSS);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA/PSS);
BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA/PSS);
+
// clang-format on
/*
@@ -560,6 +787,15 @@
*/
static void encrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+ // Skip the test for unsupported key size in StrongBox
+ if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+ (!isValidSBKeySize(transform, keySize))) {
+ state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+ " is not supported in StrongBox for algorithm: " +
+ keymintTest->getAlgorithmString(transform))
+ .c_str());
+ return;
+ }
addDefaultLabel(state);
if (!keymintTest->GenerateKey(transform, keySize)) {
state.SkipWithError(
@@ -589,6 +825,15 @@
}
static void decrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+ // Skip the test for unsupported key size in StrongBox
+ if (keymintTest->securityLevel_ == SecurityLevel::STRONGBOX &&
+ (!isValidSBKeySize(transform, keySize))) {
+ state.SkipWithError(("Skipped for STRONGBOX: Keysize: " + std::to_string(keySize) +
+ " is not supported in StrongBox for algorithm: " +
+ keymintTest->getAlgorithmString(transform))
+ .c_str());
+ return;
+ }
addDefaultLabel(state);
if (!keymintTest->GenerateKey(transform, keySize)) {
state.SkipWithError(
@@ -598,23 +843,34 @@
AuthorizationSet out_params;
AuthorizationSet in_params = keymintTest->getOperationParams(transform);
string message = keymintTest->GenerateMessage(msgSize);
- auto error = keymintTest->Begin(KeyPurpose::ENCRYPT, in_params, &out_params);
- if (error != ErrorCode::OK) {
- state.SkipWithError(
- ("Encryption begin error, " + std::to_string(keymintTest->getError())).c_str());
- return;
+ optional<string> encryptedMessage;
+
+ if (keymintTest->getAlgorithm(transform).value() == Algorithm::RSA) {
+ // Public key operation not supported, doing local Encryption
+ encryptedMessage = keymintTest->LocalRsaEncryptMessage(message, in_params);
+ if ((keySize / 8) != (*encryptedMessage).size()) {
+ state.SkipWithError("Local Encryption falied");
+ return;
+ }
+ } else {
+ auto error = keymintTest->Begin(KeyPurpose::ENCRYPT, in_params, &out_params);
+ if (error != ErrorCode::OK) {
+ state.SkipWithError(
+ ("Encryption begin error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ encryptedMessage = keymintTest->Process(message);
+ if (!encryptedMessage) {
+ state.SkipWithError(
+ ("Encryption error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ in_params.push_back(out_params);
+ out_params.Clear();
}
- auto encryptedMessage = keymintTest->Process(message);
- if (!encryptedMessage) {
- state.SkipWithError(
- ("Encryption error, " + std::to_string(keymintTest->getError())).c_str());
- return;
- }
- in_params.push_back(out_params);
- out_params.Clear();
for (auto _ : state) {
state.PauseTiming();
- error = keymintTest->Begin(KeyPurpose::DECRYPT, in_params, &out_params);
+ auto error = keymintTest->Begin(KeyPurpose::DECRYPT, in_params, &out_params);
if (error != ErrorCode::OK) {
state.SkipWithError(
("Decryption begin error, " + std::to_string(keymintTest->getError())).c_str());
@@ -649,9 +905,9 @@
BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/ECB/PKCS7Padding, 168);
#define BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(transform, msgSize) \
- BENCHMARK_KM_CIPHER(transform, 2048, msgSize) \
- BENCHMARK_KM_CIPHER(transform, 3072, msgSize) \
- BENCHMARK_KM_CIPHER(transform, 4096, msgSize)
+ BENCHMARK_KM_ASYM_CIPHER(transform, 2048, msgSize) \
+ BENCHMARK_KM_ASYM_CIPHER(transform, 3072, msgSize) \
+ BENCHMARK_KM_ASYM_CIPHER(transform, 4096, msgSize)
BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/NoPadding, SMALL_MESSAGE_SIZE);
BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/PKCS1Padding, SMALL_MESSAGE_SIZE);
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index 3f48320..efd6fc7 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -63,6 +63,9 @@
defaults: [
"keymint_use_latest_hal_aidl_ndk_shared",
],
+ static_libs: [
+ "android.hardware.security.rkp-V3-ndk",
+ ],
shared_libs: [
"libbase",
"libbinder_ndk",
@@ -78,6 +81,7 @@
name: "libkeymint_remote_prov_support_test",
srcs: ["remote_prov_utils_test.cpp"],
static_libs: [
+ "android.hardware.security.rkp-V3-ndk",
"libgmock",
"libgtest_main",
],
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index 6871e1b..1b94c62 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -181,14 +181,13 @@
* Verify the CSR as if the device is still early in the factory process and may not
* have all device identifiers provisioned yet.
*/
-ErrMsgOr<std::vector<BccEntryData>> verifyFactoryCsr(const cppbor::Array& keysToSign,
- const std::vector<uint8_t>& csr,
- IRemotelyProvisionedComponent* provisionable,
- const std::vector<uint8_t>& challenge);
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
+ const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
/**
* Verify the CSR as if the device is a final production sample.
*/
-ErrMsgOr<std::vector<BccEntryData>> verifyProductionCsr(
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge);
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index f7ab3ac..7e164fd 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -521,11 +521,10 @@
return errMsg;
}
- std::unique_ptr<cppbor::Map> parsed(parsedVerifiedDeviceInfo->asMap());
+ std::unique_ptr<cppbor::Map> parsed(parsedVerifiedDeviceInfo.release()->asMap());
if (!parsed) {
return "DeviceInfo must be a CBOR map.";
}
- parsedVerifiedDeviceInfo.release();
if (parsed->clone()->asMap()->canonicalize().encode() != deviceInfoBytes) {
return "DeviceInfo ordering is non-canonical.";
@@ -846,54 +845,79 @@
return "";
}
-ErrMsgOr<cppbor::Array> parseAndValidateCsrPayload(const cppbor::Array& keysToSign,
- const std::vector<uint8_t>& csrPayload,
- IRemotelyProvisionedComponent* provisionable,
- const std::vector<uint8_t>& challenge,
- bool isFactory) {
+ErrMsgOr<std::unique_ptr<cppbor::Array>> parseAndValidateCsrPayload(
+ const cppbor::Array& keysToSign, const std::vector<uint8_t>& csrPayload,
+ IRemotelyProvisionedComponent* provisionable, bool isFactory) {
auto [parsedCsrPayload, _, errMsg] = cppbor::parse(csrPayload);
if (!parsedCsrPayload) {
return errMsg;
}
- if (!parsedCsrPayload->asArray()) {
+
+ std::unique_ptr<cppbor::Array> parsed(parsedCsrPayload.release()->asArray());
+ if (!parsed) {
return "CSR payload is not a CBOR array.";
}
- if (parsedCsrPayload->asArray()->size() != 5U) {
- return "CSR payload must contain version, certificate type, device info, challenge, keys. "
+
+ if (parsed->size() != 4U) {
+ return "CSR payload must contain version, certificate type, device info, keys. "
"However, the parsed CSR payload has " +
- std::to_string(parsedCsrPayload->asArray()->size()) + " entries.";
+ std::to_string(parsed->size()) + " entries.";
}
- auto& signedVersion = parsedCsrPayload->asArray()->get(0);
- auto& signedCertificateType = parsedCsrPayload->asArray()->get(1);
- auto& signedDeviceInfo = parsedCsrPayload->asArray()->get(2);
- auto& signedChallenge = parsedCsrPayload->asArray()->get(3);
- auto& signedKeys = parsedCsrPayload->asArray()->get(4);
+ auto signedVersion = parsed->get(0)->asUint();
+ auto signedCertificateType = parsed->get(1)->asTstr();
+ auto signedDeviceInfo = parsed->get(2)->asMap();
+ auto signedKeys = parsed->get(3)->asArray();
- if (!signedVersion || !signedVersion->asUint() || signedVersion->asUint()->value() != 1U) {
- return "CSR payload version must be an unsigned integer and must be equal to 1.";
+ if (!signedVersion || signedVersion->value() != 3U) {
+ return "CSR payload version must be an unsigned integer and must be equal to 3.";
}
- if (!signedCertificateType || !signedCertificateType->asTstr()) {
+ if (!signedCertificateType) {
// Certificate type is allowed to be extendend by vendor, i.e. we can't
// enforce its value.
return "Certificate type must be a Tstr.";
}
- if (!signedDeviceInfo || !signedDeviceInfo->asMap()) {
+ if (!signedDeviceInfo) {
return "Device info must be an Map.";
}
- if (!signedChallenge || !signedChallenge->asBstr()) {
- return "Challenge must be a Bstr.";
- }
- if (!signedKeys || !signedKeys->asArray()) {
+ if (!signedKeys) {
return "Keys must be an Array.";
}
- auto result = parseAndValidateDeviceInfo(signedDeviceInfo->asMap()->encode(), provisionable,
- isFactory);
+ auto result = parseAndValidateDeviceInfo(signedDeviceInfo->encode(), provisionable, isFactory);
if (!result) {
return result.message();
}
+ if (signedKeys->encode() != keysToSign.encode()) {
+ return "Signed keys do not match.";
+ }
+
+ return std::move(parsed);
+}
+
+ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequestSignedPayload(
+ const std::vector<uint8_t>& signedPayload, const std::vector<uint8_t>& challenge) {
+ auto [parsedSignedPayload, _, errMsg] = cppbor::parse(signedPayload);
+ if (!parsedSignedPayload) {
+ return errMsg;
+ }
+ if (!parsedSignedPayload->asArray()) {
+ return "SignedData payload is not a CBOR array.";
+ }
+ if (parsedSignedPayload->asArray()->size() != 2U) {
+ return "SignedData payload must contain the challenge and request. However, the parsed "
+ "SignedData payload has " +
+ std::to_string(parsedSignedPayload->asArray()->size()) + " entries.";
+ }
+
+ auto signedChallenge = parsedSignedPayload->asArray()->get(0)->asBstr();
+ auto signedRequest = parsedSignedPayload->asArray()->get(1)->asBstr();
+
+ if (!signedChallenge) {
+ return "Challenge must be a Bstr.";
+ }
+
if (challenge.size() < 32 || challenge.size() > 64) {
return "Challenge size must be between 32 and 64 bytes inclusive. "
"However, challenge is " +
@@ -901,68 +925,57 @@
}
auto challengeBstr = cppbor::Bstr(challenge);
- if (*signedChallenge->asBstr() != challengeBstr) {
+ if (*signedChallenge != challengeBstr) {
return "Signed challenge does not match."
"\n Actual: " +
cppbor::prettyPrint(signedChallenge->asBstr(), 64 /* maxBStrSize */) +
"\nExpected: " + cppbor::prettyPrint(&challengeBstr, 64 /* maxBStrSize */);
}
- if (signedKeys->asArray()->encode() != keysToSign.encode()) {
- return "Signed keys do not match.";
+ if (!signedRequest) {
+ return "Request must be a Bstr.";
}
- return std::move(*parsedCsrPayload->asArray());
+ return signedRequest->value();
}
-ErrMsgOr<std::vector<BccEntryData>> verifyCsr(const cppbor::Array& keysToSign,
- const std::vector<uint8_t>& csr,
- IRemotelyProvisionedComponent* provisionable,
- const std::vector<uint8_t>& challenge,
- bool isFactory) {
- auto [parsedCsr, _, csrErrMsg] = cppbor::parse(csr);
- if (!parsedCsr) {
+ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequest(const std::vector<uint8_t>& request,
+ const std::vector<uint8_t>& challenge) {
+ auto [parsedRequest, _, csrErrMsg] = cppbor::parse(request);
+ if (!parsedRequest) {
return csrErrMsg;
}
- if (!parsedCsr->asArray()) {
- return "CSR is not a CBOR array.";
+ if (!parsedRequest->asArray()) {
+ return "AuthenticatedRequest is not a CBOR array.";
}
- if (parsedCsr->asArray()->size() != 4U) {
- return "CSR must contain version, UDS certificates, DICE chain, and signed data. "
- "However, the parsed CSR has " +
- std::to_string(parsedCsr->asArray()->size()) + " entries.";
+ if (parsedRequest->asArray()->size() != 4U) {
+ return "AuthenticatedRequest must contain version, UDS certificates, DICE chain, and "
+ "signed data. However, the parsed AuthenticatedRequest has " +
+ std::to_string(parsedRequest->asArray()->size()) + " entries.";
}
- auto& version = parsedCsr->asArray()->get(0);
- auto& udsCerts = parsedCsr->asArray()->get(1);
- auto& diceCertChain = parsedCsr->asArray()->get(2);
- auto& signedData = parsedCsr->asArray()->get(3);
+ auto version = parsedRequest->asArray()->get(0)->asUint();
+ auto udsCerts = parsedRequest->asArray()->get(1)->asMap();
+ auto diceCertChain = parsedRequest->asArray()->get(2)->asArray();
+ auto signedData = parsedRequest->asArray()->get(3)->asArray();
- if (!version || !version->asUint() || version->asUint()->value() != 3U) {
- return "Version must be an unsigned integer and must be equal to 3.";
+ if (!version || version->value() != 1U) {
+ return "AuthenticatedRequest version must be an unsigned integer and must be equal to 1.";
}
- if (!udsCerts || !udsCerts->asMap()) {
- return "UdsCerts must be an Map.";
+ if (!udsCerts) {
+ return "AuthenticatedRequest UdsCerts must be an Map.";
}
- if (!diceCertChain || !diceCertChain->asArray()) {
- return "DiceCertChain must be an Array.";
+ if (!diceCertChain) {
+ return "AuthenticatedRequest DiceCertChain must be an Array.";
}
- if (!signedData || !signedData->asArray()) {
- return "SignedData must be an Array.";
- }
-
- RpcHardwareInfo info;
- provisionable->getHardwareInfo(&info);
- if (version->asUint()->value() != info.versionNumber) {
- return "CSR version (" + std::to_string(version->asUint()->value()) +
- ") does not match the remotely provisioned component version (" +
- std::to_string(info.versionNumber) + ").";
+ if (!signedData) {
+ return "AuthenticatedRequest SignedData must be an Array.";
}
// DICE chain is [ pubkey, + DiceChainEntry ]. Its format is the same as BCC from RKP v1-2.
- auto diceContents = validateBcc(diceCertChain->asArray());
+ auto diceContents = validateBcc(diceCertChain);
if (!diceContents) {
- return diceContents.message() + "\n" + prettyPrint(diceCertChain.get());
+ return diceContents.message() + "\n" + prettyPrint(diceCertChain);
}
if (diceContents->size() == 0U) {
return "The DICE chain is empty. It must contain at least one entry.";
@@ -970,33 +983,51 @@
auto& udsPub = diceContents->back().pubKey;
- auto error = validateUdsCerts(*udsCerts->asMap(), udsPub);
+ auto error = validateUdsCerts(*udsCerts, udsPub);
if (!error.empty()) {
return error;
}
- auto csrPayload = verifyAndParseCoseSign1(signedData->asArray(), udsPub, {} /* aad */);
+ auto signedPayload = verifyAndParseCoseSign1(signedData, udsPub, {} /* aad */);
+ if (!signedPayload) {
+ return signedPayload.message();
+ }
+
+ auto payload = parseAndValidateAuthenticatedRequestSignedPayload(*signedPayload, challenge);
+ if (!payload) {
+ return payload.message();
+ }
+
+ return payload;
+}
+
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyCsr(const cppbor::Array& keysToSign,
+ const std::vector<uint8_t>& csr,
+ IRemotelyProvisionedComponent* provisionable,
+ const std::vector<uint8_t>& challenge,
+ bool isFactory) {
+ RpcHardwareInfo info;
+ provisionable->getHardwareInfo(&info);
+ if (info.versionNumber != 3) {
+ return "Remotely provisioned component version (" + std::to_string(info.versionNumber) +
+ ") does not match expected version (3).";
+ }
+
+ auto csrPayload = parseAndValidateAuthenticatedRequest(csr, challenge);
if (!csrPayload) {
return csrPayload.message();
}
- auto parsedCsrPayload = parseAndValidateCsrPayload(keysToSign, *csrPayload, provisionable,
- challenge, isFactory);
- if (!parsedCsrPayload) {
- return parsedCsrPayload.message();
- }
-
- return *diceContents;
+ return parseAndValidateCsrPayload(keysToSign, *csrPayload, provisionable, isFactory);
}
-ErrMsgOr<std::vector<BccEntryData>> verifyFactoryCsr(const cppbor::Array& keysToSign,
- const std::vector<uint8_t>& csr,
- IRemotelyProvisionedComponent* provisionable,
- const std::vector<uint8_t>& challenge) {
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyFactoryCsr(
+ const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
+ IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/true);
}
-ErrMsgOr<std::vector<BccEntryData>> verifyProductionCsr(
+ErrMsgOr<std::unique_ptr<cppbor::Array>> verifyProductionCsr(
const cppbor::Array& keysToSign, const std::vector<uint8_t>& csr,
IRemotelyProvisionedComponent* provisionable, const std::vector<uint8_t>& challenge) {
return verifyCsr(keysToSign, csr, provisionable, challenge, /*isFactory=*/false);
diff --git a/security/keymint/RKP_CHANGELOG.md b/security/rkp/CHANGELOG.md
similarity index 74%
rename from security/keymint/RKP_CHANGELOG.md
rename to security/rkp/CHANGELOG.md
index 243fc26..29b1a1c 100644
--- a/security/keymint/RKP_CHANGELOG.md
+++ b/security/rkp/CHANGELOG.md
@@ -19,6 +19,12 @@
* `uniqueId` String added as a field in order to differentiate IRPC instances on device.
## IRemotelyProvisionedComponent 2 -> 3
+* The RKP HAL now builds separately from KeyMint.
+ * The HAL remains under the `android.hardware.security.keymint` package for
+ compatibility with previous releases. ABI compatibility requires this.
+ * Dependencies on the RKP HAL must add a dependency on
+ `"android.hardware.security.rkp"` generated code (instead of
+ `"android.hardward.security.keymint"`).
* ProtectedData has been removed.
* DeviceInfo
* `version` has moved to a top-level field within the CSR generated by the HAL
@@ -30,4 +36,5 @@
* the chain of signing, MACing, and encryption operations has been replaced with a single
COSE_Sign1 object.
* CertificateType has been added to identify the type of certificate being requested.
-
+* RpcHardwareInfo
+ * `supportedNumKeysInCsr` added to report the maximum number of keys supported in a CSR.
diff --git a/security/keymint/RKP_README.md b/security/rkp/README.md
similarity index 95%
rename from security/keymint/RKP_README.md
rename to security/rkp/README.md
index 89a2598..5fb4948 100644
--- a/security/keymint/RKP_README.md
+++ b/security/rkp/README.md
@@ -6,8 +6,8 @@
keys. The HAL must interact effectively with Keystore (and other daemons) and
protect device privacy and security.
-Note that this API is designed for KeyMint, but with the intention that it
-should be usable for other HALs that require certificate provisioning.
+Note that this API was originally designed for KeyMint, with the intention that
+it should be usable for other HALs that require certificate provisioning.
Throughout this document we'll refer to the Keystore and KeyMint (formerly
called Keymaster) components, but only for concreteness and convenience; those
labels could be replaced with the names of any system and secure area
@@ -312,7 +312,7 @@
```
Please see
-[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl)
for a full CDDL definition of the BCC.
### `CertificateRequest`
@@ -366,9 +366,9 @@
following links:
* [IRemotelyProvisionedComponent
- HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl)
-* [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl)
-* [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl)
-* [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
-* [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
+ HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl)
+* [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl)
+* [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl)
+* [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl)
+* [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl)
diff --git a/security/rkp/aidl/Android.bp b/security/rkp/aidl/Android.bp
new file mode 100644
index 0000000..4c479f4
--- /dev/null
+++ b/security/rkp/aidl/Android.bp
@@ -0,0 +1,37 @@
+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.security.rkp",
+ vendor_available: true,
+ srcs: [
+ // This HAL was originally part of keymint.
+ "android/hardware/security/keymint/*.aidl",
+
+ // in the future
+ // "android/hardware/security/rkp/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ min_sdk_version: "33",
+ },
+ rust: {
+ enabled: true,
+ },
+ },
+ versions_with_info: [
+ {
+ version: "1",
+ },
+ {
+ version: "2",
+ },
+ ],
+}
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash
new file mode 100644
index 0000000..404553b
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/.hash
@@ -0,0 +1 @@
+d285480d2e0002adc0ace80edf34aa725679512e
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/1/android/hardware/security/keymint/RpcHardwareInfo.aidl
diff --git a/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash
new file mode 100644
index 0000000..8700d33
--- /dev/null
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/.hash
@@ -0,0 +1 @@
+c8d34e56ae0807b61f028019622d8b60a37e0a8b
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/2/android/hardware/security/keymint/RpcHardwareInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 95%
rename from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
index 5ff45f8..b1f99e1 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/security/rkp/aidl/aidl_api/android.hardware.security.rkp/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -39,7 +39,9 @@
@utf8InCpp String rpcAuthorName;
int supportedEekCurve = 0;
@nullable @utf8InCpp String uniqueId;
+ int supportedNumKeysInCsr = 4;
const int CURVE_NONE = 0;
const int CURVE_P256 = 1;
const int CURVE_25519 = 2;
+ const int MIN_SUPPORTED_NUM_KEYS_IN_CSR = 20;
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
similarity index 100%
rename from security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/DeviceInfo.aidl
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
similarity index 98%
rename from security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index 86c1717..78969d1 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -315,13 +315,12 @@
*
* @return the following CBOR Certificate Signing Request (Csr) serialized into a byte array:
*
- * Csr = AuthenticatedMessage<CsrPayload>
+ * Csr = AuthenticatedRequest<CsrPayload>
*
* CsrPayload = [ ; CBOR Array defining the payload for Csr
- * version: 1, ; The CsrPayload CDDL Schema version.
+ * version: 3, ; The CsrPayload CDDL Schema version.
* CertificateType, ; The type of certificate being requested.
* DeviceInfo, ; Defined in DeviceInfo.aidl
- * challenge: bstr .size (32..64), ; Provided by the method parameters
* KeysToSign, ; Provided by the method parameters
* ]
*
@@ -335,11 +334,14 @@
*
* KeysToSign = [ * PublicKey ] ; Please see MacedPublicKey.aidl for the PublicKey definition.
*
- * AuthenticatedMessage<T> = [
- * version: 3, ; The AuthenticatedMessage CDDL Schema version.
- * UdsCerts,
- * DiceCertChain,
- * SignedData<T>,
+ * AuthenticatedRequest<T> = [
+ * version: 1, ; The AuthenticatedRequest CDDL Schema version.
+ * UdsCerts,
+ * DiceCertChain,
+ * SignedData<[
+ * challenge: bstr .size (32..64), ; Provided by the method parameters
+ * bstr .cbor T,
+ * ]>,
* ]
*
* ; COSE_Sign1 (untagged)
diff --git a/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
similarity index 100%
rename from security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
similarity index 100%
rename from security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
diff --git a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl b/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
similarity index 87%
rename from security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
rename to security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
index 0cb33ce..5fe5b00 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl
@@ -74,4 +74,17 @@
*
*/
@nullable @utf8InCpp String uniqueId;
+
+ /**
+ * supportedNumKeysInCsr is the maximum number of keys in a CSR that this implementation can
+ * support. This value is implementation defined.
+ *
+ * From version 3 onwards, supportedNumKeysInCsr must be larger or equal to
+ * MIN_SUPPORTED_NUM_KEYS_IN_CSR.
+ *
+ * The default value was chosen as the value enforced by the VTS test in versions 1 and 2 of
+ * this interface.
+ */
+ const int MIN_SUPPORTED_NUM_KEYS_IN_CSR = 20;
+ int supportedNumKeysInCsr = 4;
}
diff --git a/sensors/aidl/Android.bp b/sensors/aidl/Android.bp
index d04017c..9673190 100644
--- a/sensors/aidl/Android.bp
+++ b/sensors/aidl/Android.bp
@@ -11,6 +11,7 @@
name: "android.hardware.sensors",
vendor_available: true,
srcs: ["android/hardware/sensors/*.aidl"],
+ host_supported: true,
imports: [
"android.hardware.common-V2",
"android.hardware.common.fmq-V1",
diff --git a/sensors/aidl/convert/Android.bp b/sensors/aidl/convert/Android.bp
new file mode 100644
index 0000000..8e2146d
--- /dev/null
+++ b/sensors/aidl/convert/Android.bp
@@ -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 {
+ // 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"],
+}
+
+cc_library_static {
+ name: "android.hardware.sensors-V1-convert",
+ vendor_available: true,
+ srcs: ["convert.cpp"],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libhardware",
+ "libbase",
+ "libutils",
+ "android.hardware.sensors-V1-ndk",
+ ],
+ 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
new file mode 100644
index 0000000..415f435
--- /dev/null
+++ b/sensors/aidl/convert/convert.cpp
@@ -0,0 +1,496 @@
+/*
+ * 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 "aidl/sensors/convert.h"
+#include "android-base/logging.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+using aidl::android::hardware::sensors::AdditionalInfo;
+using aidl::android::hardware::sensors::DynamicSensorInfo;
+using aidl::android::hardware::sensors::Event;
+using aidl::android::hardware::sensors::ISensors;
+using aidl::android::hardware::sensors::SensorInfo;
+using aidl::android::hardware::sensors::SensorStatus;
+using aidl::android::hardware::sensors::SensorType;
+
+status_t convertToStatus(ndk::ScopedAStatus status) {
+ if (status.isOk()) {
+ return OK;
+ } else {
+ switch (status.getExceptionCode()) {
+ case EX_ILLEGAL_ARGUMENT: {
+ return BAD_VALUE;
+ }
+ case EX_SECURITY: {
+ return PERMISSION_DENIED;
+ }
+ case EX_UNSUPPORTED_OPERATION: {
+ return INVALID_OPERATION;
+ }
+ case EX_SERVICE_SPECIFIC: {
+ switch (status.getServiceSpecificError()) {
+ case ISensors::ERROR_BAD_VALUE: {
+ return BAD_VALUE;
+ }
+ case ISensors::ERROR_NO_MEMORY: {
+ return NO_MEMORY;
+ }
+ default: {
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+ default: {
+ return UNKNOWN_ERROR;
+ }
+ }
+ }
+}
+
+void convertToSensor(const SensorInfo& src, sensor_t* dst) {
+ dst->name = strdup(src.name.c_str());
+ dst->vendor = strdup(src.vendor.c_str());
+ dst->version = src.version;
+ dst->handle = src.sensorHandle;
+ dst->type = (int)src.type;
+ dst->maxRange = src.maxRange;
+ dst->resolution = src.resolution;
+ dst->power = src.power;
+ dst->minDelay = src.minDelayUs;
+ dst->fifoReservedEventCount = src.fifoReservedEventCount;
+ dst->fifoMaxEventCount = src.fifoMaxEventCount;
+ dst->stringType = strdup(src.typeAsString.c_str());
+ dst->requiredPermission = strdup(src.requiredPermission.c_str());
+ dst->maxDelay = src.maxDelayUs;
+ dst->flags = src.flags;
+ dst->reserved[0] = dst->reserved[1] = 0;
+}
+
+void convertToSensorEvent(const Event& src, sensors_event_t* dst) {
+ *dst = {.version = sizeof(sensors_event_t),
+ .sensor = src.sensorHandle,
+ .type = (int32_t)src.sensorType,
+ .reserved0 = 0,
+ .timestamp = src.timestamp};
+
+ switch (src.sensorType) {
+ case SensorType::META_DATA: {
+ // Legacy HALs expect the handle reference in the meta data field.
+ // Copy it over from the handle of the event.
+ dst->meta_data.what = (int32_t)src.payload.get<Event::EventPayload::meta>().what;
+ dst->meta_data.sensor = src.sensorHandle;
+ // Set the sensor handle to 0 to maintain compatibility.
+ dst->sensor = 0;
+ break;
+ }
+
+ case SensorType::ACCELEROMETER:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::GYROSCOPE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION: {
+ dst->acceleration.x = src.payload.get<Event::EventPayload::vec3>().x;
+ dst->acceleration.y = src.payload.get<Event::EventPayload::vec3>().y;
+ dst->acceleration.z = src.payload.get<Event::EventPayload::vec3>().z;
+ dst->acceleration.status = (int32_t)src.payload.get<Event::EventPayload::vec3>().status;
+ break;
+ }
+
+ case SensorType::GAME_ROTATION_VECTOR: {
+ dst->data[0] = src.payload.get<Event::EventPayload::vec4>().x;
+ dst->data[1] = src.payload.get<Event::EventPayload::vec4>().y;
+ dst->data[2] = src.payload.get<Event::EventPayload::vec4>().z;
+ dst->data[3] = src.payload.get<Event::EventPayload::vec4>().w;
+ break;
+ }
+
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+ dst->data[0] = src.payload.get<Event::EventPayload::data>().values[0];
+ dst->data[1] = src.payload.get<Event::EventPayload::data>().values[1];
+ dst->data[2] = src.payload.get<Event::EventPayload::data>().values[2];
+ dst->data[3] = src.payload.get<Event::EventPayload::data>().values[3];
+ dst->data[4] = src.payload.get<Event::EventPayload::data>().values[4];
+ break;
+ }
+
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::ACCELEROMETER_UNCALIBRATED: {
+ dst->uncalibrated_gyro.x_uncalib = src.payload.get<Event::EventPayload::uncal>().x;
+ dst->uncalibrated_gyro.y_uncalib = src.payload.get<Event::EventPayload::uncal>().y;
+ dst->uncalibrated_gyro.z_uncalib = src.payload.get<Event::EventPayload::uncal>().z;
+ dst->uncalibrated_gyro.x_bias = src.payload.get<Event::EventPayload::uncal>().xBias;
+ dst->uncalibrated_gyro.y_bias = src.payload.get<Event::EventPayload::uncal>().yBias;
+ dst->uncalibrated_gyro.z_bias = src.payload.get<Event::EventPayload::uncal>().zBias;
+ break;
+ }
+
+ case SensorType::HINGE_ANGLE:
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::LIGHT:
+ case SensorType::PRESSURE:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::STATIONARY_DETECT:
+ case SensorType::MOTION_DETECT:
+ case SensorType::HEART_BEAT:
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
+ dst->data[0] = src.payload.get<Event::EventPayload::scalar>();
+ break;
+ }
+
+ case SensorType::STEP_COUNTER: {
+ dst->u64.step_counter = src.payload.get<Event::EventPayload::stepCount>();
+ break;
+ }
+
+ case SensorType::HEART_RATE: {
+ dst->heart_rate.bpm = src.payload.get<Event::EventPayload::heartRate>().bpm;
+ dst->heart_rate.status =
+ (int8_t)src.payload.get<Event::EventPayload::heartRate>().status;
+ break;
+ }
+
+ case SensorType::POSE_6DOF: { // 15 floats
+ for (size_t i = 0; i < 15; ++i) {
+ dst->data[i] = src.payload.get<Event::EventPayload::pose6DOF>().values[i];
+ }
+ break;
+ }
+
+ case SensorType::DYNAMIC_SENSOR_META: {
+ dst->dynamic_sensor_meta.connected =
+ src.payload.get<Event::EventPayload::dynamic>().connected;
+ dst->dynamic_sensor_meta.handle =
+ src.payload.get<Event::EventPayload::dynamic>().sensorHandle;
+ dst->dynamic_sensor_meta.sensor = NULL; // to be filled in later
+
+ memcpy(dst->dynamic_sensor_meta.uuid,
+ src.payload.get<Event::EventPayload::dynamic>().uuid.values.data(), 16);
+
+ break;
+ }
+
+ case SensorType::ADDITIONAL_INFO: {
+ const AdditionalInfo& srcInfo = src.payload.get<Event::EventPayload::additional>();
+
+ additional_info_event_t* dstInfo = &dst->additional_info;
+ dstInfo->type = (int32_t)srcInfo.type;
+ dstInfo->serial = srcInfo.serial;
+
+ switch (srcInfo.payload.getTag()) {
+ case AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32: {
+ const auto& values =
+ srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataInt32>()
+ .values;
+ CHECK_EQ(values.size() * sizeof(int32_t), sizeof(dstInfo->data_int32));
+ memcpy(dstInfo->data_int32, values.data(), sizeof(dstInfo->data_int32));
+ break;
+ }
+ case AdditionalInfo::AdditionalInfoPayload::Tag::dataFloat: {
+ const auto& values =
+ srcInfo.payload.get<AdditionalInfo::AdditionalInfoPayload::dataFloat>()
+ .values;
+ CHECK_EQ(values.size() * sizeof(float), sizeof(dstInfo->data_float));
+ memcpy(dstInfo->data_float, values.data(), sizeof(dstInfo->data_float));
+ break;
+ }
+ default: {
+ LOG(ERROR) << "Invalid sensor additional info tag: ",
+ (int)srcInfo.payload.getTag();
+ }
+ }
+ break;
+ }
+
+ case SensorType::HEAD_TRACKER: {
+ const auto& ht = src.payload.get<Event::EventPayload::headTracker>();
+ dst->head_tracker.rx = ht.rx;
+ dst->head_tracker.ry = ht.ry;
+ dst->head_tracker.rz = ht.rz;
+ dst->head_tracker.vx = ht.vx;
+ dst->head_tracker.vy = ht.vy;
+ dst->head_tracker.vz = ht.vz;
+ dst->head_tracker.discontinuity_count = ht.discontinuityCount;
+ break;
+ }
+
+ case SensorType::ACCELEROMETER_LIMITED_AXES:
+ case SensorType::GYROSCOPE_LIMITED_AXES:
+ dst->limited_axes_imu.x = src.payload.get<Event::EventPayload::limitedAxesImu>().x;
+ dst->limited_axes_imu.y = src.payload.get<Event::EventPayload::limitedAxesImu>().y;
+ dst->limited_axes_imu.z = src.payload.get<Event::EventPayload::limitedAxesImu>().z;
+ dst->limited_axes_imu.x_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImu>().xSupported;
+ dst->limited_axes_imu.y_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImu>().ySupported;
+ dst->limited_axes_imu.z_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImu>().zSupported;
+ break;
+
+ case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+ case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED:
+ dst->limited_axes_imu_uncalibrated.x_uncalib =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().x;
+ dst->limited_axes_imu_uncalibrated.y_uncalib =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().y;
+ dst->limited_axes_imu_uncalibrated.z_uncalib =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().z;
+ dst->limited_axes_imu_uncalibrated.x_bias =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xBias;
+ dst->limited_axes_imu_uncalibrated.y_bias =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().yBias;
+ dst->limited_axes_imu_uncalibrated.z_bias =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zBias;
+ dst->limited_axes_imu_uncalibrated.x_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().xSupported;
+ dst->limited_axes_imu_uncalibrated.y_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().ySupported;
+ dst->limited_axes_imu_uncalibrated.z_supported =
+ src.payload.get<Event::EventPayload::limitedAxesImuUncal>().zSupported;
+ break;
+
+ case SensorType::HEADING:
+ dst->heading.heading = src.payload.get<Event::EventPayload::heading>().heading;
+ dst->heading.accuracy = src.payload.get<Event::EventPayload::heading>().accuracy;
+ break;
+
+ default: {
+ CHECK_GE((int32_t)src.sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+ memcpy(dst->data, src.payload.get<Event::EventPayload::data>().values.data(),
+ 16 * sizeof(float));
+ break;
+ }
+ }
+}
+
+void convertFromSensorEvent(const sensors_event_t& src, Event* dst) {
+ *dst = {
+ .timestamp = src.timestamp,
+ .sensorHandle = src.sensor,
+ .sensorType = (SensorType)src.type,
+ };
+
+ switch (dst->sensorType) {
+ case SensorType::META_DATA: {
+ Event::EventPayload::MetaData meta;
+ meta.what = (Event::EventPayload::MetaData::MetaDataEventType)src.meta_data.what;
+ // Legacy HALs contain the handle reference in the meta data field.
+ // Copy that over to the handle of the event. In legacy HALs this
+ // field was expected to be 0.
+ dst->sensorHandle = src.meta_data.sensor;
+ dst->payload.set<Event::EventPayload::Tag::meta>(meta);
+ break;
+ }
+
+ case SensorType::ACCELEROMETER:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::GYROSCOPE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION: {
+ Event::EventPayload::Vec3 vec3;
+ vec3.x = src.acceleration.x;
+ vec3.y = src.acceleration.y;
+ vec3.z = src.acceleration.z;
+ vec3.status = (SensorStatus)src.acceleration.status;
+ dst->payload.set<Event::EventPayload::Tag::vec3>(vec3);
+ break;
+ }
+
+ case SensorType::GAME_ROTATION_VECTOR: {
+ Event::EventPayload::Vec4 vec4;
+ vec4.x = src.data[0];
+ vec4.y = src.data[1];
+ vec4.z = src.data[2];
+ vec4.w = src.data[3];
+ dst->payload.set<Event::EventPayload::Tag::vec4>(vec4);
+ break;
+ }
+
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+ Event::EventPayload::Data data;
+ memcpy(data.values.data(), src.data, 5 * sizeof(float));
+ dst->payload.set<Event::EventPayload::Tag::data>(data);
+ break;
+ }
+
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::ACCELEROMETER_UNCALIBRATED: {
+ Event::EventPayload::Uncal uncal;
+ uncal.x = src.uncalibrated_gyro.x_uncalib;
+ uncal.y = src.uncalibrated_gyro.y_uncalib;
+ uncal.z = src.uncalibrated_gyro.z_uncalib;
+ uncal.xBias = src.uncalibrated_gyro.x_bias;
+ uncal.yBias = src.uncalibrated_gyro.y_bias;
+ uncal.zBias = src.uncalibrated_gyro.z_bias;
+ dst->payload.set<Event::EventPayload::Tag::uncal>(uncal);
+ break;
+ }
+
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::LIGHT:
+ case SensorType::PRESSURE:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::STATIONARY_DETECT:
+ case SensorType::MOTION_DETECT:
+ case SensorType::HEART_BEAT:
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT:
+ case SensorType::HINGE_ANGLE: {
+ dst->payload.set<Event::EventPayload::Tag::scalar>((float)src.data[0]);
+ break;
+ }
+
+ case SensorType::STEP_COUNTER: {
+ dst->payload.set<Event::EventPayload::Tag::stepCount>(src.u64.step_counter);
+ break;
+ }
+
+ case SensorType::HEART_RATE: {
+ Event::EventPayload::HeartRate heartRate;
+ heartRate.bpm = src.heart_rate.bpm;
+ heartRate.status = (SensorStatus)src.heart_rate.status;
+ dst->payload.set<Event::EventPayload::Tag::heartRate>(heartRate);
+ break;
+ }
+
+ case SensorType::POSE_6DOF: { // 15 floats
+ Event::EventPayload::Pose6Dof pose6DOF;
+ for (size_t i = 0; i < 15; ++i) {
+ pose6DOF.values[i] = src.data[i];
+ }
+ dst->payload.set<Event::EventPayload::Tag::pose6DOF>(pose6DOF);
+ break;
+ }
+
+ case SensorType::DYNAMIC_SENSOR_META: {
+ DynamicSensorInfo dynamic;
+ dynamic.connected = src.dynamic_sensor_meta.connected;
+ dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
+
+ memcpy(dynamic.uuid.values.data(), src.dynamic_sensor_meta.uuid, 16);
+ dst->payload.set<Event::EventPayload::Tag::dynamic>(dynamic);
+ break;
+ }
+
+ case SensorType::ADDITIONAL_INFO: {
+ AdditionalInfo info;
+ const additional_info_event_t& srcInfo = src.additional_info;
+ info.type = (AdditionalInfo::AdditionalInfoType)srcInfo.type;
+ info.serial = srcInfo.serial;
+
+ AdditionalInfo::AdditionalInfoPayload::Int32Values data;
+ CHECK_EQ(data.values.size() * sizeof(int32_t), sizeof(srcInfo.data_int32));
+ memcpy(data.values.data(), srcInfo.data_int32, sizeof(srcInfo.data_int32));
+ info.payload.set<AdditionalInfo::AdditionalInfoPayload::Tag::dataInt32>(data);
+
+ dst->payload.set<Event::EventPayload::Tag::additional>(info);
+ break;
+ }
+
+ case SensorType::HEAD_TRACKER: {
+ Event::EventPayload::HeadTracker headTracker;
+ headTracker.rx = src.head_tracker.rx;
+ headTracker.ry = src.head_tracker.ry;
+ headTracker.rz = src.head_tracker.rz;
+ headTracker.vx = src.head_tracker.vx;
+ headTracker.vy = src.head_tracker.vy;
+ headTracker.vz = src.head_tracker.vz;
+ headTracker.discontinuityCount = src.head_tracker.discontinuity_count;
+
+ dst->payload.set<Event::EventPayload::Tag::headTracker>(headTracker);
+ break;
+ }
+
+ case SensorType::ACCELEROMETER_LIMITED_AXES:
+ case SensorType::GYROSCOPE_LIMITED_AXES: {
+ Event::EventPayload::LimitedAxesImu limitedAxesImu;
+ limitedAxesImu.x = src.limited_axes_imu.x;
+ limitedAxesImu.y = src.limited_axes_imu.y;
+ limitedAxesImu.z = src.limited_axes_imu.z;
+ limitedAxesImu.xSupported = src.limited_axes_imu.x_supported;
+ limitedAxesImu.ySupported = src.limited_axes_imu.y_supported;
+ limitedAxesImu.zSupported = src.limited_axes_imu.z_supported;
+ dst->payload.set<Event::EventPayload::Tag::limitedAxesImu>(limitedAxesImu);
+ break;
+ }
+
+ case SensorType::ACCELEROMETER_LIMITED_AXES_UNCALIBRATED:
+ case SensorType::GYROSCOPE_LIMITED_AXES_UNCALIBRATED: {
+ Event::EventPayload::LimitedAxesImuUncal limitedAxesImuUncal;
+ limitedAxesImuUncal.x = src.limited_axes_imu_uncalibrated.x_uncalib;
+ limitedAxesImuUncal.y = src.limited_axes_imu_uncalibrated.y_uncalib;
+ limitedAxesImuUncal.z = src.limited_axes_imu_uncalibrated.z_uncalib;
+ limitedAxesImuUncal.xBias = src.limited_axes_imu_uncalibrated.x_bias;
+ limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
+ limitedAxesImuUncal.yBias = src.limited_axes_imu_uncalibrated.y_bias;
+ limitedAxesImuUncal.zBias = src.limited_axes_imu_uncalibrated.z_bias;
+ limitedAxesImuUncal.xSupported = src.limited_axes_imu_uncalibrated.x_supported;
+ limitedAxesImuUncal.ySupported = src.limited_axes_imu_uncalibrated.y_supported;
+ limitedAxesImuUncal.zSupported = src.limited_axes_imu_uncalibrated.z_supported;
+ dst->payload.set<Event::EventPayload::Tag::limitedAxesImuUncal>(limitedAxesImuUncal);
+ break;
+ }
+
+ case SensorType::HEADING: {
+ Event::EventPayload::Heading heading;
+ heading.heading = src.heading.heading;
+ heading.accuracy = src.heading.accuracy;
+ dst->payload.set<Event::EventPayload::heading>(heading);
+ break;
+ }
+
+ default: {
+ CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+ Event::EventPayload::Data data;
+ memcpy(data.values.data(), src.data, 16 * sizeof(float));
+ dst->payload.set<Event::EventPayload::Tag::data>(data);
+ break;
+ }
+ }
+}
+
+} // namespace implementation
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/aidl/convert/include/aidl/sensors/convert.h b/sensors/aidl/convert/include/aidl/sensors/convert.h
new file mode 100644
index 0000000..702b226
--- /dev/null
+++ b/sensors/aidl/convert/include/aidl/sensors/convert.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <aidl/android/hardware/sensors/ISensors.h>
+#include <hardware/sensors.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace implementation {
+
+status_t convertToStatus(ndk::ScopedAStatus status);
+void convertToSensor(const aidl::android::hardware::sensors::SensorInfo& src, sensor_t* dst);
+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);
+
+} // namespace implementation
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/usb/1.0/default/Android.bp b/usb/1.0/default/Android.bp
index 4bed2c7..5f56fe0 100644
--- a/usb/1.0/default/Android.bp
+++ b/usb/1.0/default/Android.bp
@@ -21,21 +21,11 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-filegroup {
- name: "android.hardware.usb@1.0-service.xml",
- srcs: ["android.hardware.usb@1.0-service.xml"],
-}
-
-filegroup {
- name: "android.hardware.usb@1.0-service.rc",
- srcs: ["android.hardware.usb@1.0-service.rc"],
-}
-
cc_binary {
name: "android.hardware.usb@1.0-service",
defaults: ["hidl_defaults"],
- init_rc: [":android.hardware.usb@1.0-service.rc"],
- vintf_fragments: [":android.hardware.usb@1.0-service.xml"],
+ init_rc: ["android.hardware.usb@1.0-service.rc"],
+ vintf_fragments: ["android.hardware.usb@1.0-service.xml"],
relative_install_path: "hw",
vendor: true,
srcs: [
diff --git a/usb/1.0/default/apex/manifest.json b/usb/1.0/default/apex/manifest.json
deleted file mode 100644
index 6a1095f..0000000
--- a/usb/1.0/default/apex/manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.android.hardware.usb",
- "version": 1
-}
diff --git a/usb/aidl/default/Android.bp b/usb/aidl/default/Android.bp
index 7cb2822..ad331f9 100644
--- a/usb/aidl/default/Android.bp
+++ b/usb/aidl/default/Android.bp
@@ -37,8 +37,18 @@
"android.hardware.usb-V1-ndk",
"libbase",
"libbinder_ndk",
- "libcutils",
+ "libcutils",
"liblog",
"libutils",
],
}
+
+filegroup {
+ name: "android.hardware.usb-service.example.xml",
+ srcs: ["android.hardware.usb-service.example.xml"],
+}
+
+filegroup {
+ name: "android.hardware.usb-service.example.rc",
+ srcs: ["android.hardware.usb-service.example.rc"],
+}
diff --git a/usb/1.0/default/apex/Android.bp b/usb/apex/Android.bp
similarity index 84%
rename from usb/1.0/default/apex/Android.bp
rename to usb/apex/Android.bp
index ee50fdf..765aa21 100644
--- a/usb/1.0/default/apex/Android.bp
+++ b/usb/apex/Android.bp
@@ -27,19 +27,6 @@
certificate: "com.android.hardware.usb",
}
-genrule {
- name: "com.android.hardware.usb.rc-gen",
- srcs: [":android.hardware.usb@1.0-service.rc"],
- out: ["com.android.hardware.usb.rc"],
- cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.usb/' $(in) > $(out)",
-}
-
-prebuilt_etc {
- name: "com.android.hardware.usb.rc",
- src: ":com.android.hardware.usb.rc-gen",
- installable: false,
-}
-
apex {
name: "com.android.hardware.usb",
manifest: "manifest.json",
@@ -49,11 +36,25 @@
updatable: false,
soc_specific: true,
use_vndk_as_stable: true,
- binaries: ["android.hardware.usb@1.0-service"],
+ binaries: ["android.hardware.usb-service.example"],
prebuilts: [
- "com.android.hardware.usb.rc",
+ "com.android.hardware.usb.rc", // init .rc
"android.hardware.usb.accessory.prebuilt.xml",
"android.hardware.usb.host.prebuilt.xml",
],
- vintf_fragments: [":android.hardware.usb@1.0-service.xml"],
+ vintf_fragments: [":android.hardware.usb-service.example.xml"],
+}
+
+// Replace the binary path from /vendor/bin to /apex/{name}/bin in the init .rc file
+genrule {
+ name: "com.android.hardware.usb.rc-gen",
+ srcs: [":android.hardware.usb-service.example.rc"],
+ out: ["com.android.hardware.usb.rc"],
+ cmd: "sed -E 's/\\/vendor/\\/apex\\/com.android.hardware.usb/' $(in) > $(out)",
+}
+
+prebuilt_etc {
+ name: "com.android.hardware.usb.rc",
+ src: ":com.android.hardware.usb.rc-gen",
+ installable: false,
}
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.avbpubkey b/usb/apex/com.android.hardware.usb.avbpubkey
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.avbpubkey
rename to usb/apex/com.android.hardware.usb.avbpubkey
Binary files differ
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.pem b/usb/apex/com.android.hardware.usb.pem
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.pem
rename to usb/apex/com.android.hardware.usb.pem
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.pk8 b/usb/apex/com.android.hardware.usb.pk8
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.pk8
rename to usb/apex/com.android.hardware.usb.pk8
Binary files differ
diff --git a/usb/1.0/default/apex/com.android.hardware.usb.x509.pem b/usb/apex/com.android.hardware.usb.x509.pem
similarity index 100%
rename from usb/1.0/default/apex/com.android.hardware.usb.x509.pem
rename to usb/apex/com.android.hardware.usb.x509.pem
diff --git a/usb/1.0/default/apex/file_contexts b/usb/apex/file_contexts
similarity index 66%
rename from usb/1.0/default/apex/file_contexts
rename to usb/apex/file_contexts
index bc84ac4..f223a56 100644
--- a/usb/1.0/default/apex/file_contexts
+++ b/usb/apex/file_contexts
@@ -2,4 +2,4 @@
# Permission XMLs
/etc/permissions(/.*)? u:object_r:vendor_configs_file:s0
# binary
-/bin/hw/android\.hardware\.usb@1\.0-service u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
+/bin/hw/android\.hardware\.usb-service\.example u:object_r:hal_usb_default_exec:s0
\ No newline at end of file
diff --git a/usb/apex/manifest.json b/usb/apex/manifest.json
new file mode 100644
index 0000000..1a41b90
--- /dev/null
+++ b/usb/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.usb",
+ "version": 1
+}
diff --git a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
index fa50821..0924da7 100644
--- a/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
+++ b/usb/gadget/1.2/default/lib/UsbGadgetUtils.cpp
@@ -170,7 +170,6 @@
if ((functions & GadgetFunction::RNDIS) != 0) {
ALOGI("setCurrentUsbFunctions rndis");
- if (linkFunction("gsi.rndis", (*functionCount)++)) return Status::ERROR;
std::string rndisFunction = GetProperty(kVendorRndisConfig, "");
if (rndisFunction != "") {
if (linkFunction(rndisFunction.c_str(), (*functionCount)++)) return Status::ERROR;
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 39bb5d9..6ec8d57 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
@@ -48,4 +48,5 @@
SUPPORTED_RANGE_DATA_NTF_CONFIG = 229,
SUPPORTED_RSSI_REPORTING = 230,
SUPPORTED_DIAGNOSTICS = 231,
+ SUPPORTED_MIN_SLOT_DURATION = 232,
}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
index 86479fb..b182f9d 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorCapabilityTlvTypes.aidl
@@ -179,4 +179,9 @@
* 0 - Feature not supported.
*/
SUPPORTED_DIAGNOSTICS = 0xE7,
+
+ /**
+ * 4 byte value to indicate supported min slot duration in ms.
+ */
+ SUPPORTED_MIN_SLOT_DURATION = 0xE8,
}
diff --git a/wifi/1.6/default/wifi_legacy_hal.cpp b/wifi/1.6/default/wifi_legacy_hal.cpp
index c9bcdc5..43cb7c4 100644
--- a/wifi/1.6/default/wifi_legacy_hal.cpp
+++ b/wifi/1.6/default/wifi_legacy_hal.cpp
@@ -366,6 +366,14 @@
}
}
+// Callback to report cached scan results
+std::function<void(wifi_cached_scan_report*)> on_cached_scan_results_internal_callback;
+void onSyncCachedScanResults(wifi_cached_scan_report* cache_report) {
+ if (on_cached_scan_results_internal_callback) {
+ on_cached_scan_results_internal_callback(cache_report);
+ }
+}
+
// End of the free-standing "C" style callbacks.
WifiLegacyHal::WifiLegacyHal(const std::weak_ptr<wifi_system::InterfaceTool> iface_tool,
@@ -1589,6 +1597,17 @@
return global_func_table_.wifi_enable_tx_power_limits(getIfaceHandle(iface_name), enable);
}
+wifi_error WifiLegacyHal::getWifiCachedScanResults(
+ const std::string& iface_name, const CachedScanResultsCallbackHandlers& handler) {
+ on_cached_scan_results_internal_callback = handler.on_cached_scan_results;
+
+ wifi_error status = global_func_table_.wifi_get_cached_scan_results(getIfaceHandle(iface_name),
+ {onSyncCachedScanResults});
+
+ on_cached_scan_results_internal_callback = nullptr;
+ return status;
+}
+
void WifiLegacyHal::invalidate() {
global_handle_ = nullptr;
iface_name_to_handle_.clear();
diff --git a/wifi/1.6/default/wifi_legacy_hal.h b/wifi/1.6/default/wifi_legacy_hal.h
index 2b923b4..1fd784a 100644
--- a/wifi/1.6/default/wifi_legacy_hal.h
+++ b/wifi/1.6/default/wifi_legacy_hal.h
@@ -218,6 +218,7 @@
using ::WIFI_BAND_ABG_WITH_DFS;
using ::WIFI_BAND_BG;
using ::WIFI_BAND_UNSPECIFIED;
+using ::wifi_cached_scan_report;
using ::wifi_cached_scan_results;
using ::WIFI_CHAN_WIDTH_10;
using ::WIFI_CHAN_WIDTH_160;
@@ -465,6 +466,12 @@
std::function<void(chre_nan_rtt_state)> on_wifi_chre_nan_rtt_state;
};
+// Cached Scan Results response and event callbacks struct.
+struct CachedScanResultsCallbackHandlers {
+ // Callback for Cached Scan Results
+ std::function<void(wifi_cached_scan_report*)> on_cached_scan_results;
+};
+
/**
* Class that encapsulates all legacy HAL interactions.
* This class manages the lifetime of the event loop thread used by legacy HAL.
@@ -684,6 +691,8 @@
const ChreCallbackHandlers& handler);
wifi_error enableWifiTxPowerLimits(const std::string& iface_name, bool enable);
+ wifi_error getWifiCachedScanResults(const std::string& iface_name,
+ const CachedScanResultsCallbackHandlers& handler);
private:
// Retrieve interface handles for all the available interfaces.
diff --git a/wifi/1.6/default/wifi_legacy_hal_stubs.cpp b/wifi/1.6/default/wifi_legacy_hal_stubs.cpp
index b3bd373..8f8527a 100644
--- a/wifi/1.6/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.6/default/wifi_legacy_hal_stubs.cpp
@@ -167,6 +167,7 @@
populateStubFor(&hal_fn->wifi_nan_rtt_chre_disable_request);
populateStubFor(&hal_fn->wifi_chre_register_handler);
populateStubFor(&hal_fn->wifi_enable_tx_power_limits);
+ populateStubFor(&hal_fn->wifi_get_cached_scan_results);
return true;
}
} // namespace legacy_hal
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index 8d9f498..da3ca52 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -52,4 +52,5 @@
oneway void onStaDeauthorized(in byte[] srcAddress, in byte[] p2pDeviceAddress);
oneway void onGroupFrequencyChanged(in String groupIfname, in int frequency);
oneway void onDeviceFoundWithVendorElements(in byte[] srcAddress, in byte[] p2pDeviceAddress, in byte[] primaryDeviceType, in String deviceName, in android.hardware.wifi.supplicant.WpsConfigMethods configMethods, in byte deviceCapabilities, in android.hardware.wifi.supplicant.P2pGroupCapabilityMask groupCapabilities, in byte[] wfdDeviceInfo, in byte[] wfdR2DeviceInfo, in byte[] vendorElemBytes);
+ oneway void onGroupStartedWithParams(in android.hardware.wifi.supplicant.P2pGroupStartedEventParams groupStartedEventParams);
}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
similarity index 77%
copy from security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
index 5ff45f8..19611a9 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/RpcHardwareInfo.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -31,15 +31,16 @@
// 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.security.keymint;
-/* @hide */
-@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
-parcelable RpcHardwareInfo {
- int versionNumber;
- @utf8InCpp String rpcAuthorName;
- int supportedEekCurve = 0;
- @nullable @utf8InCpp String uniqueId;
- const int CURVE_NONE = 0;
- const int CURVE_P256 = 1;
- const int CURVE_25519 = 2;
+package android.hardware.wifi.supplicant;
+@VintfStability
+parcelable P2pGroupStartedEventParams {
+ String groupInterfaceName;
+ boolean isGroupOwner;
+ byte[] ssid;
+ int frequencyMHz;
+ byte[] psk;
+ String passphrase;
+ boolean isPersistent;
+ byte[] goDeviceAddress;
+ byte[] goInterfaceAddress;
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
index 7c8c1f2..9d6fa67 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantP2pIfaceCallback.aidl
@@ -17,6 +17,7 @@
package android.hardware.wifi.supplicant;
import android.hardware.wifi.supplicant.P2pGroupCapabilityMask;
+import android.hardware.wifi.supplicant.P2pGroupStartedEventParams;
import android.hardware.wifi.supplicant.P2pProvDiscStatusCode;
import android.hardware.wifi.supplicant.P2pStatusCode;
import android.hardware.wifi.supplicant.WpsConfigMethods;
@@ -243,4 +244,11 @@
in byte[] primaryDeviceType, in String deviceName, in WpsConfigMethods configMethods,
in byte deviceCapabilities, in P2pGroupCapabilityMask groupCapabilities,
in byte[] wfdDeviceInfo, in byte[] wfdR2DeviceInfo, in byte[] vendorElemBytes);
+
+ /**
+ * Used to indicate the start of a P2P group, with some parameters describing the group.
+ *
+ * @param groupStartedEventParams Parameters describing the P2P group.
+ */
+ void onGroupStartedWithParams(in P2pGroupStartedEventParams groupStartedEventParams);
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.aidl
new file mode 100644
index 0000000..a04153a
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/P2pGroupStartedEventParams.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.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Parameters passed as part of Wifi P2P group start event.
+ */
+@VintfStability
+parcelable P2pGroupStartedEventParams {
+ /** Interface name of the group (For ex: p2p-p2p0-1). */
+ String groupInterfaceName;
+
+ /** Whether this device is owner of the group. */
+ boolean isGroupOwner;
+
+ /** SSID of the group. */
+ byte[] ssid;
+
+ /** Frequency in MHz on which this group is created. */
+ int frequencyMHz;
+
+ /** PSK used to secure the group. */
+ byte[] psk;
+
+ /** PSK passphrase used to secure the group. */
+ String passphrase;
+
+ /** Whether this group is persisted or not. */
+ boolean isPersistent;
+
+ /** MAC Address of the owner of this group. */
+ byte[/* 6 */] goDeviceAddress;
+
+ /** MAC Address of the P2P interface of the owner of this group. */
+ byte[/* 6 */] goInterfaceAddress;
+}
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
index 8e142ec..b959c75 100644
--- a/wifi/supplicant/aidl/vts/functional/Android.bp
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -44,7 +44,7 @@
"android.hardware.wifi@1.5",
"android.hardware.wifi.supplicant@1.0",
"android.hardware.wifi.supplicant@1.1",
- "android.hardware.wifi.supplicant-V1-ndk",
+ "android.hardware.wifi.supplicant-V2-ndk",
"libwifi-system",
"libwifi-system-iface",
"VtsHalWifiV1_0TargetTestUtil",
@@ -78,7 +78,7 @@
"android.hardware.wifi@1.5",
"android.hardware.wifi.supplicant@1.0",
"android.hardware.wifi.supplicant@1.1",
- "android.hardware.wifi.supplicant-V1-ndk",
+ "android.hardware.wifi.supplicant-V2-ndk",
"libwifi-system",
"libwifi-system-iface",
"VtsHalWifiV1_0TargetTestUtil",
@@ -112,7 +112,7 @@
"android.hardware.wifi@1.5",
"android.hardware.wifi.supplicant@1.0",
"android.hardware.wifi.supplicant@1.1",
- "android.hardware.wifi.supplicant-V1-ndk",
+ "android.hardware.wifi.supplicant-V2-ndk",
"libwifi-system",
"libwifi-system-iface",
"VtsHalWifiV1_0TargetTestUtil",
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
index b7984fa..ee0eff5 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
@@ -37,6 +37,7 @@
using aidl::android::hardware::wifi::supplicant::MiracastMode;
using aidl::android::hardware::wifi::supplicant::P2pFrameTypeMask;
using aidl::android::hardware::wifi::supplicant::P2pGroupCapabilityMask;
+using aidl::android::hardware::wifi::supplicant::P2pGroupStartedEventParams;
using aidl::android::hardware::wifi::supplicant::P2pProvDiscStatusCode;
using aidl::android::hardware::wifi::supplicant::P2pStatusCode;
using aidl::android::hardware::wifi::supplicant::SupplicantStatusCode;
@@ -177,6 +178,10 @@
const std::vector<uint8_t>& /* vendorElemBytes */) override {
return ndk::ScopedAStatus::ok();
}
+ ::ndk::ScopedAStatus onGroupStartedWithParams(
+ const P2pGroupStartedEventParams& /* groupStartedEventParams */) override {
+ return ndk::ScopedAStatus::ok();
+ }
};
class SupplicantP2pIfaceAidlTest : public testing::TestWithParam<std::string> {