Merge "Add README files to VHAL codebase."
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 30e88b5..dd2b4e0 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -78,6 +78,7 @@
"android/hardware/audio/core/IModule.aidl",
"android/hardware/audio/core/IStreamIn.aidl",
"android/hardware/audio/core/IStreamOut.aidl",
+ "android/hardware/audio/core/ModuleDebug.aidl",
],
imports: [
"android.hardware.audio.common-V1",
@@ -94,6 +95,4 @@
},
},
},
- versions: [
- ],
}
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 33e8290..f8bc2c7 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
@@ -34,11 +34,15 @@
package android.hardware.audio.core;
@VintfStability
interface IModule {
+ void setModuleDebug(in android.hardware.audio.core.ModuleDebug debug);
+ android.media.audio.common.AudioPort connectExternalDevice(in android.media.audio.common.AudioPort templateIdAndAdditionalData);
+ void disconnectExternalDevice(int portId);
android.hardware.audio.core.AudioPatch[] getAudioPatches();
android.media.audio.common.AudioPort getAudioPort(int portId);
android.media.audio.common.AudioPortConfig[] getAudioPortConfigs();
android.media.audio.common.AudioPort[] getAudioPorts();
android.hardware.audio.core.AudioRoute[] getAudioRoutes();
+ android.hardware.audio.core.AudioRoute[] getAudioRoutesForAudioPort(int portId);
android.hardware.audio.core.IStreamIn openInputStream(int portConfigId, in android.hardware.audio.common.SinkMetadata sinkMetadata);
android.hardware.audio.core.IStreamOut openOutputStream(int portConfigId, in android.hardware.audio.common.SourceMetadata sourceMetadata, in @nullable android.media.audio.common.AudioOffloadInfo offloadInfo);
android.hardware.audio.core.AudioPatch setAudioPatch(in android.hardware.audio.core.AudioPatch requested);
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.aidl
new file mode 100644
index 0000000..80ee185
--- /dev/null
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ModuleDebug.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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.audio.core;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ModuleDebug {
+ boolean simulateDeviceConnections;
+}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index d47ea3c..f406cd8 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -22,6 +22,7 @@
import android.hardware.audio.core.AudioRoute;
import android.hardware.audio.core.IStreamIn;
import android.hardware.audio.core.IStreamOut;
+import android.hardware.audio.core.ModuleDebug;
import android.media.audio.common.AudioOffloadInfo;
import android.media.audio.common.AudioPort;
import android.media.audio.common.AudioPortConfig;
@@ -44,6 +45,116 @@
@VintfStability
interface IModule {
/**
+ * Sets debugging configuration for the HAL module. This method is only
+ * called during xTS testing and is intended for validating the aspects of
+ * the HAL module behavior that would otherwise require human intervention.
+ *
+ * The HAL module must throw an error if there is an attempt to change
+ * the debug behavior for the aspect which is currently in use.
+ *
+ * @param debug The debug options.
+ * @throws EX_ILLEGAL_STATE If the flag(s) being changed affect functionality
+ * which is currently in use.
+ */
+ void setModuleDebug(in ModuleDebug debug);
+
+ /**
+ * 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
+ * been connected to a device port selected using the 'id' field of the
+ * input AudioPort parameter. This device port must have dynamic profiles
+ * (an empty list of profiles). This port is further referenced to as "port
+ * template" because it acts as a template for creating a new instance of a
+ * "connected" device port which gets returned from this method.
+ *
+ * The input AudioPort parameter may contain any additional data obtained by
+ * the system side from other subsystems. The nature of data depends on the
+ * type of the connection. For example, for point-to-multipoint external
+ * device connections, the input parameter may contain the address of the
+ * connected external device. Another example is EDID information for HDMI
+ * connections (ExtraAudioDescriptor), which can be provided by the HDMI-CEC
+ * HAL module.
+ *
+ * It is the responsibility of the HAL module to query audio profiles
+ * supported by the connected device and return them as part of the returned
+ * AudioPort instance. In the case when the HAL is unable to query the
+ * external device, an error must be thrown.
+ *
+ * Thus, the returned audio port instance is the result of combining the
+ * following information:
+ * - a unique port ID generated by the HAL module;
+ * - static information from the port template;
+ * - list of audio profiles supported by the connected device;
+ * - additional data from the input AudioPort parameter.
+ *
+ * The HAL module must also update the list of audio routes to include the
+ * ID of the instantiated connected device port. Normally, the connected
+ * port allows the same routing as the port template.
+ *
+ * Also see notes on 'ModuleDebug.simulateDeviceConnections'.
+ *
+ * The following protocol is used by HAL module client for handling
+ * connection of an external device:
+ * 1. Obtain the list of device ports and their IDs via 'getAudioPorts'
+ * method. Select the appropriate port template using
+ * AudioDeviceDescription ('ext.device' field of AudioPort).
+ * 2. Combine the ID of the port template with any additional data and call
+ * 'connectExternalDevice'. The HAL module returns a new instance of
+ * AudioPort created using the rules explained above. Both
+ * 'getAudioPort' and 'getAudioPorts' methods will be returning the same
+ * information for this port until disconnection.
+ * 3. Configure the connected port with one of supported profiles using
+ * 'setAudioPortConfig'.
+ * 4. Query the list of AudioRoutes for the new AudioPort using
+ * 'getAudioRoutesForAudioPort' or 'getAudioRoutes' methods.
+ *
+ * External devices are distinguished by the connection type and device
+ * address. Calling this method multiple times to inform about connection of
+ * the same external device without disconnecting it first is an error.
+ *
+ * The HAL module must perform validation of the input parameter and throw
+ * an error if it is lacking required information, for example, when no
+ * device address is specified for a point-to-multipoint external device
+ * connection.
+ *
+ * Handling of a disconnect is done in a reverse order:
+ * 1. Reset port configuration using the 'resetAudioPortConfig' method.
+ * 2. Release the connected device port by calling the 'disconnectExternalDevice'
+ * method. This also removes the audio routes associated with this
+ * device port.
+ *
+ * @return New instance of an audio port for the connected external device.
+ * @param templateIdAndAdditionalData Specifies port template ID and any
+ * additional data.
+ * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+ * - If the template port can not be found by the ID.
+ * - If the template is not a device port, or
+ * it does not have dynamic profiles.
+ * - If the input parameter is lacking required
+ * information.
+ * @throws EX_ILLEGAL_STATE In the following cases:
+ * - If the HAL module is unable to query audio profiles.
+ * - If the external device has already been connected.
+ */
+ AudioPort connectExternalDevice(in AudioPort templateIdAndAdditionalData);
+
+ /**
+ * Set a device port of a an external device into disconnected state.
+ *
+ * This method is used to inform the HAL module that an external device has
+ * been disconnected. The 'portId' must be of a connected device port
+ * instance previously instantiated using the 'connectExternalDevice'
+ * method.
+ *
+ * @throws EX_ILLEGAL_ARGUMENT In the following cases:
+ * - If the port can not be found by the ID.
+ * - If this is not a connected device port.
+ * @throws EX_ILLEGAL_STATE If the port has active configurations.
+ */
+ void disconnectExternalDevice(int portId);
+
+ /**
* Return all audio patches of this module.
*
* Returns a list of audio patches, that is, established connections between
@@ -57,12 +168,10 @@
* Return the current state of the audio port.
*
* Using the port ID provided on input, returns the current state of the
- * audio port. For device port representing a connection to some external
- * device, e.g. over HDMI or USB, currently supported audio profiles and
- * extra audio descriptors may change.
- *
- * For all other audio ports it must be the same configuration as returned
- * for this port ID by 'getAudioPorts'.
+ * audio port. The values of the AudioPort structure must be the same as
+ * currently returned by the 'getAudioPorts' method. The 'getAudioPort'
+ * method is provided to reduce overhead in the case when the client needs
+ * to check the state of one port only.
*
* @return The current state of an audio port.
* @param portId The ID of the audio port.
@@ -87,33 +196,45 @@
AudioPortConfig[] getAudioPortConfigs();
/**
- * Return all audio ports provided by this module.
+ * Return the current state of all audio ports provided by this module.
*
- * Returns a list of all mix ports and device ports provided by this
- * module. Each returned port must have a unique ID within this module
- * ('AudioPort.id' field). The returned list must not change during
- * the lifetime of the IModule instance. For audio ports with dynamic
- * profiles (changing depending on external devices being connected
- * to the system) an empty list of profiles must be returned. The list
- * of currently supported audio profiles is obtained from 'getAudioPort'
- * method.
+ * Returns a list of all mix ports and device ports provided by this HAL
+ * module, reflecting their current states. Each returned port must have a
+ * unique ID within this module ('AudioPort.id' field). The list also
+ * includes "connected" ports created using 'connectExternalDevice' method.
*
* @return The list of audio ports.
*/
AudioPort[] getAudioPorts();
/**
- * Return all audio routes of this module.
+ * Return all current audio routes of this module.
*
- * Returns a list of audio routes, that is, allowed connections between
- * audio ports. The returned list must not change during the lifetime of the
- * IModule instance.
+ * Returns the current list of audio routes, that is, allowed connections
+ * between audio ports. The list can change when new device audio ports
+ * get created as a result of connecting or disconnecting of external
+ * devices.
*
* @return The list of audio routes.
*/
AudioRoute[] getAudioRoutes();
/**
+ * Return audio routes related to the specified audio port.
+ *
+ * Returns the list of audio routes that include the specified port ID
+ * as a source or as a sink. The returned list is a subset of the result
+ * returned by the 'getAudioRoutes' method, filtered by the port ID.
+ * An empty list can be returned, indicating that the audio port can not
+ * be used for creating audio patches.
+ *
+ * @return The list of audio routes.
+ * @param portId The ID of the audio port.
+ * @throws EX_ILLEGAL_ARGUMENT If the port can not be found by the ID.
+ */
+ AudioRoute[] getAudioRoutesForAudioPort(int portId);
+
+ /**
* Open an input stream using an existing audio mix port configuration.
*
* The audio port configuration ID must be obtained by calling
@@ -230,6 +351,10 @@
* parameter. The framework can then set the suggested configuration on a
* subsequent retry call to this method.
*
+ * Device ports with dynamic audio profiles (an empty list of profiles)
+ * can not be used with this method. The list of profiles must be filled in
+ * as a result of calling 'connectExternalDevice' method.
+ *
* @return Whether the requested configuration has been applied.
* @param requested Requested audio port configuration.
* @param suggested Same as requested configuration, if it was applied.
@@ -241,7 +366,7 @@
* - If the port can not be found by the port ID.
* - If it is not possible to generate a suggested port
* configuration, for example, if the port only has dynamic
- * profiles and they are currently empty.
+ * profiles.
*/
boolean setAudioPortConfig(in AudioPortConfig requested, out AudioPortConfig suggested);
diff --git a/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl b/audio/aidl/android/hardware/audio/core/ModuleDebug.aidl
new file mode 100644
index 0000000..858a9bd
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/ModuleDebug.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;
+
+/**
+ * This structure contains flags used for enabling various debugging aspects
+ * in a HAL module. By default, all debugging aspects are turned off. They
+ * can be enabled during xTS tests for functionality that, for example, would
+ * otherwise require human intervention (e.g. connection of external devices).
+ */
+@JavaDerive(equals=true, toString=true)
+@VintfStability
+parcelable ModuleDebug {
+ /**
+ * When set to 'true', HAL module must simulate connection of external
+ * devices. An external device becomes 'connected' after a call to
+ * IModule.connectExternalDevice, simulation of connection requires:
+ * - provision of at least one non-dynamic device port profile on
+ * connection (as if it was retrieved from a connected device);
+ * - simulating successful application of port configurations for reported
+ * profiles.
+ */
+ boolean simulateDeviceConnections;
+}
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 0a6fe60..4728a89 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -13,6 +13,7 @@
shared_libs: [
"libbase",
"libbinder_ndk",
+ "android.media.audio.common.types-V1-ndk",
"android.hardware.audio.core-V1-ndk",
],
export_include_dirs: ["include"],
@@ -36,6 +37,7 @@
shared_libs: [
"libbase",
"libbinder_ndk",
+ "android.media.audio.common.types-V1-ndk",
"android.hardware.audio.core-V1-ndk",
],
static_libs: [
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index 1104caa..19d0b3c 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -16,14 +16,15 @@
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
#include <aidl/android/media/audio/common/AudioDeviceType.h>
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
#include <aidl/android/media/audio/common/AudioFormatType.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
-#include "aidl/android/media/audio/common/AudioFormatDescription.h"
#include "core-impl/Configuration.h"
using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDeviceDescription;
using aidl::android::media::audio::common::AudioDeviceType;
using aidl::android::media::audio::common::AudioFormatDescription;
using aidl::android::media::audio::common::AudioFormatType;
@@ -54,9 +55,11 @@
return profile;
}
-static AudioPortExt createDeviceExt(AudioDeviceType devType, int32_t flags) {
+static AudioPortExt createDeviceExt(AudioDeviceType devType, int32_t flags,
+ std::string connection = "") {
AudioPortDeviceExt deviceExt;
deviceExt.device.type.type = devType;
+ deviceExt.device.type.connection = std::move(connection);
deviceExt.flags = flags;
return AudioPortExt::make<AudioPortExt::Tag::device>(deviceExt);
}
@@ -102,8 +105,64 @@
return route;
}
+// Configuration:
+//
+// Device ports:
+// * "Null", OUT_SPEAKER, default
+// - no profiles specified
+// * "Loopback Out", OUT_SUBMIX
+// - profile PCM 24-bit; STEREO; 48000
+// * "USB Out", OUT_DEVICE, CONNECTION_USB
+// - no profiles specified
+// * "Zero", IN_MICROPHONE, default
+// - no profiles specified
+// * "Loopback In", IN_SUBMIX
+// - profile PCM 24-bit; STEREO; 48000
+// * "USB In", IN_DEVICE, CONNECTION_USB
+// - no profiles specified
+//
+// Mix ports:
+// * "primary output", PRIMARY, 1 max open, 1 max active stream
+// - profile PCM 16-bit; MONO, STEREO; 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+// * "loopback output", stream count unlimited
+// - profile PCM 24-bit; STEREO; 48000
+// * "primary input", 2 max open, 2 max active streams
+// - profile PCM 16-bit; MONO, STEREO, FRONT_BACK;
+// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
+// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+// * "loopback input", stream count unlimited
+// - profile PCM 24-bit; STEREO; 48000
+//
+// Routes:
+// "primary out" -> "Null"
+// "primary out" -> "USB Out"
+// "loopback out" -> "Loopback Out"
+// "Zero", "USB In" -> "primary input"
+// "Loopback In" -> "loopback input"
+//
+// Initial port configs:
+// * "Null" device port: PCM 24-bit; STEREO; 48000
+// * "Zero" device port: PCM 24-bit; MONO; 48000
+//
+// Profiles for device port connected state:
+// * USB Out":
+// - profile PCM 16-bit; MONO, STEREO; 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+// * USB In":
+// - profile PCM 16-bit; MONO, STEREO; 44100, 48000
+// - profile PCM 24-bit; MONO, STEREO; 44100, 48000
+//
Configuration& getNullPrimaryConfiguration() {
static Configuration configuration = []() {
+ const std::vector<AudioProfile> standardPcmAudioProfiles = {
+ createProfile(PcmType::INT_16_BIT,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+ {44100, 48000}),
+ createProfile(PcmType::INT_24_BIT,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+ {44100, 48000})};
Configuration c;
AudioPort nullOutDevice =
@@ -111,27 +170,19 @@
createDeviceExt(AudioDeviceType::OUT_SPEAKER,
1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
c.ports.push_back(nullOutDevice);
-
- AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output",
- 1 << static_cast<int32_t>(AudioOutputFlags::PRIMARY),
- false, createPortMixExt(1, 1));
- primaryOutMix.profiles.push_back(
- createProfile(PcmType::INT_16_BIT,
- {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
- {44100, 48000}));
- primaryOutMix.profiles.push_back(
- createProfile(PcmType::INT_24_BIT,
- {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
- {44100, 48000}));
- c.ports.push_back(primaryOutMix);
-
- c.routes.push_back(createRoute({primaryOutMix.id}, nullOutDevice.id));
-
c.initialConfigs.push_back(
createPortConfig(nullOutDevice.id, nullOutDevice.id, PcmType::INT_24_BIT,
AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
createDeviceExt(AudioDeviceType::OUT_SPEAKER, 0)));
+ AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output",
+ 1 << static_cast<int32_t>(AudioOutputFlags::PRIMARY),
+ false, createPortMixExt(1, 1));
+ primaryOutMix.profiles.insert(primaryOutMix.profiles.begin(),
+ standardPcmAudioProfiles.begin(),
+ standardPcmAudioProfiles.end());
+ c.ports.push_back(primaryOutMix);
+
AudioPort loopOutDevice = createPort(c.nextPortId++, "Loopback Out", 0, false,
createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0));
loopOutDevice.profiles.push_back(
@@ -144,13 +195,22 @@
createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
c.ports.push_back(loopOutMix);
- c.routes.push_back(createRoute({loopOutMix.id}, loopOutDevice.id));
+ AudioPort usbOutDevice =
+ createPort(c.nextPortId++, "USB Out", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
+ AudioDeviceDescription::CONNECTION_USB));
+ c.ports.push_back(usbOutDevice);
+ c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles;
AudioPort zeroInDevice =
createPort(c.nextPortId++, "Zero", 0, true,
createDeviceExt(AudioDeviceType::IN_MICROPHONE,
1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE));
c.ports.push_back(zeroInDevice);
+ c.initialConfigs.push_back(
+ createPortConfig(zeroInDevice.id, zeroInDevice.id, PcmType::INT_24_BIT,
+ AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
+ createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
AudioPort primaryInMix =
createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(2, 2));
@@ -166,13 +226,6 @@
{8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
c.ports.push_back(primaryInMix);
- c.routes.push_back(createRoute({zeroInDevice.id}, primaryInMix.id));
-
- c.initialConfigs.push_back(
- createPortConfig(zeroInDevice.id, zeroInDevice.id, PcmType::INT_24_BIT,
- AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
- createDeviceExt(AudioDeviceType::IN_MICROPHONE, 0)));
-
AudioPort loopInDevice = createPort(c.nextPortId++, "Loopback In", 0, true,
createDeviceExt(AudioDeviceType::IN_SUBMIX, 0));
loopInDevice.profiles.push_back(
@@ -185,6 +238,16 @@
createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
c.ports.push_back(loopInMix);
+ AudioPort usbInDevice = createPort(c.nextPortId++, "USB In", 0, true,
+ createDeviceExt(AudioDeviceType::IN_DEVICE, 0,
+ AudioDeviceDescription::CONNECTION_USB));
+ c.ports.push_back(usbInDevice);
+ c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles;
+
+ c.routes.push_back(createRoute({primaryOutMix.id}, nullOutDevice.id));
+ c.routes.push_back(createRoute({primaryOutMix.id}, usbOutDevice.id));
+ c.routes.push_back(createRoute({loopOutMix.id}, loopOutDevice.id));
+ c.routes.push_back(createRoute({zeroInDevice.id, usbInDevice.id}, primaryInMix.id));
c.routes.push_back(createRoute({loopInDevice.id}, loopInMix.id));
c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index e0a68a5..961ee84 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -18,7 +18,6 @@
#include <set>
#define LOG_TAG "AHAL_Module"
-#define LOG_NDEBUG 0
#include <android-base/logging.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
@@ -81,6 +80,7 @@
}
return false;
}
+
} // namespace
void Module::cleanUpPatch(int32_t patchId) {
@@ -135,6 +135,154 @@
do_insert(patch.sinkPortConfigIds);
}
+ndk::ScopedAStatus Module::setModuleDebug(
+ const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) {
+ LOG(DEBUG) << __func__ << ": old flags:" << mDebug.toString()
+ << ", new flags: " << in_debug.toString();
+ if (mDebug.simulateDeviceConnections != in_debug.simulateDeviceConnections &&
+ !mConnectedDevicePorts.empty()) {
+ LOG(ERROR) << __func__ << ": attempting to change device connections simulation "
+ << "while having external devices connected";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ mDebug = in_debug;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::connectExternalDevice(const AudioPort& in_templateIdAndAdditionalData,
+ AudioPort* _aidl_return) {
+ const int32_t templateId = in_templateIdAndAdditionalData.id;
+ auto& ports = getConfig().ports;
+ AudioPort connectedPort;
+ { // Scope the template port so that we don't accidentally modify it.
+ auto templateIt = findById<AudioPort>(ports, templateId);
+ if (templateIt == ports.end()) {
+ LOG(ERROR) << __func__ << ": port id " << templateId << " not found";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (templateIt->ext.getTag() != AudioPortExt::Tag::device) {
+ LOG(ERROR) << __func__ << ": port id " << templateId << " is not a device port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (!templateIt->profiles.empty()) {
+ LOG(ERROR) << __func__ << ": port id " << templateId
+ << " does not have dynamic profiles";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ auto& templateDevicePort = templateIt->ext.get<AudioPortExt::Tag::device>();
+ if (templateDevicePort.device.type.connection.empty()) {
+ LOG(ERROR) << __func__ << ": port id " << templateId << " is permanently attached";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ // Postpone id allocation until we ensure that there are no client errors.
+ connectedPort = *templateIt;
+ connectedPort.extraAudioDescriptors = in_templateIdAndAdditionalData.extraAudioDescriptors;
+ const auto& inputDevicePort =
+ in_templateIdAndAdditionalData.ext.get<AudioPortExt::Tag::device>();
+ auto& connectedDevicePort = connectedPort.ext.get<AudioPortExt::Tag::device>();
+ connectedDevicePort.device.address = inputDevicePort.device.address;
+ LOG(DEBUG) << __func__ << ": device port " << connectedPort.id << " device set to "
+ << connectedDevicePort.device.toString();
+ // Check if there is already a connected port with for the same external device.
+ for (auto connectedPortId : mConnectedDevicePorts) {
+ auto connectedPortIt = findById<AudioPort>(ports, connectedPortId);
+ if (connectedPortIt->ext.get<AudioPortExt::Tag::device>().device ==
+ connectedDevicePort.device) {
+ LOG(ERROR) << __func__ << ": device " << connectedDevicePort.device.toString()
+ << " is already connected at the device port id " << connectedPortId;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ }
+ }
+
+ if (!mDebug.simulateDeviceConnections) {
+ // In a real HAL here we would attempt querying the profiles from the device.
+ LOG(ERROR) << __func__ << ": failed to query supported device profiles";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ connectedPort.id = ++getConfig().nextPortId;
+ mConnectedDevicePorts.insert(connectedPort.id);
+ LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
+ << "connected port ID " << connectedPort.id;
+ auto& connectedProfiles = getConfig().connectedProfiles;
+ if (auto connectedProfilesIt = connectedProfiles.find(templateId);
+ connectedProfilesIt != connectedProfiles.end()) {
+ connectedPort.profiles = connectedProfilesIt->second;
+ }
+ ports.push_back(connectedPort);
+ *_aidl_return = std::move(connectedPort);
+
+ std::vector<AudioRoute> newRoutes;
+ auto& routes = getConfig().routes;
+ for (auto& r : routes) {
+ if (r.sinkPortId == templateId) {
+ AudioRoute newRoute;
+ newRoute.sourcePortIds = r.sourcePortIds;
+ newRoute.sinkPortId = connectedPort.id;
+ newRoute.isExclusive = r.isExclusive;
+ newRoutes.push_back(std::move(newRoute));
+ } else {
+ auto& srcs = r.sourcePortIds;
+ if (std::find(srcs.begin(), srcs.end(), templateId) != srcs.end()) {
+ srcs.push_back(connectedPort.id);
+ }
+ }
+ }
+ routes.insert(routes.end(), newRoutes.begin(), newRoutes.end());
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::disconnectExternalDevice(int32_t in_portId) {
+ auto& ports = getConfig().ports;
+ auto portIt = findById<AudioPort>(ports, in_portId);
+ if (portIt == ports.end()) {
+ LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (portIt->ext.getTag() != AudioPortExt::Tag::device) {
+ LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a device port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (mConnectedDevicePorts.count(in_portId) == 0) {
+ LOG(ERROR) << __func__ << ": port id " << in_portId << " is not a connected device port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ auto& configs = getConfig().portConfigs;
+ auto& initials = getConfig().initialConfigs;
+ auto configIt = std::find_if(configs.begin(), configs.end(), [&](const auto& config) {
+ if (config.portId == in_portId) {
+ // Check if the configuration was provided by the client.
+ const auto& initialIt = findById<AudioPortConfig>(initials, config.id);
+ return initialIt == initials.end() || config != *initialIt;
+ }
+ return false;
+ });
+ if (configIt != configs.end()) {
+ LOG(ERROR) << __func__ << ": port id " << in_portId << " has a non-default config with id "
+ << configIt->id;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ ports.erase(portIt);
+ mConnectedDevicePorts.erase(in_portId);
+ LOG(DEBUG) << __func__ << ": connected device port " << in_portId << " released";
+
+ auto& routes = getConfig().routes;
+ for (auto routesIt = routes.begin(); routesIt != routes.end();) {
+ if (routesIt->sinkPortId == in_portId) {
+ routesIt = routes.erase(routesIt);
+ } else {
+ // Note: the list of sourcePortIds can't become empty because there must
+ // be the id of the template port in the route.
+ erase_if(routesIt->sourcePortIds, [in_portId](auto src) { return src == in_portId; });
+ ++routesIt;
+ }
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus Module::getAudioPatches(std::vector<AudioPatch>* _aidl_return) {
*_aidl_return = getConfig().patches;
LOG(DEBUG) << __func__ << ": returning " << _aidl_return->size() << " patches";
@@ -171,6 +319,23 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Module::getAudioRoutesForAudioPort(int32_t in_portId,
+ std::vector<AudioRoute>* _aidl_return) {
+ auto& ports = getConfig().ports;
+ if (auto portIt = findById<AudioPort>(ports, in_portId); portIt == ports.end()) {
+ LOG(ERROR) << __func__ << ": port id " << in_portId << " not found";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ auto& routes = getConfig().routes;
+ std::copy_if(routes.begin(), routes.end(), std::back_inserter(*_aidl_return),
+ [&](const auto& r) {
+ const auto& srcs = r.sourcePortIds;
+ return r.sinkPortId == in_portId ||
+ std::find(srcs.begin(), srcs.end(), in_portId) != srcs.end();
+ });
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus Module::openInputStream(int32_t in_portConfigId,
const SinkMetadata& in_sinkMetadata,
std::shared_ptr<IStreamIn>* _aidl_return) {
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
index 17e342d..d5cd30b 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -16,6 +16,7 @@
#pragma once
+#include <map>
#include <vector>
#include <aidl/android/hardware/audio/core/AudioPatch.h>
@@ -29,6 +30,9 @@
std::vector<::aidl::android::media::audio::common::AudioPort> ports;
std::vector<::aidl::android::media::audio::common::AudioPortConfig> portConfigs;
std::vector<::aidl::android::media::audio::common::AudioPortConfig> initialConfigs;
+ // Port id -> List of profiles to use when the device port state is set to 'connected'.
+ std::map<int32_t, std::vector<::aidl::android::media::audio::common::AudioProfile>>
+ connectedProfiles;
std::vector<AudioRoute> routes;
std::vector<AudioPatch> patches;
int32_t nextPortId = 1;
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 359626c..81a02ba 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -18,6 +18,7 @@
#include <map>
#include <memory>
+#include <set>
#include <aidl/android/hardware/audio/core/BnModule.h>
@@ -27,6 +28,12 @@
namespace aidl::android::hardware::audio::core {
class Module : public BnModule {
+ ndk::ScopedAStatus setModuleDebug(
+ const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
+ ndk::ScopedAStatus connectExternalDevice(
+ const ::aidl::android::media::audio::common::AudioPort& in_templateIdAndAdditionalData,
+ ::aidl::android::media::audio::common::AudioPort* _aidl_return) override;
+ ndk::ScopedAStatus disconnectExternalDevice(int32_t in_portId) override;
ndk::ScopedAStatus getAudioPatches(std::vector<AudioPatch>* _aidl_return) override;
ndk::ScopedAStatus getAudioPort(
int32_t in_portId,
@@ -37,6 +44,9 @@
ndk::ScopedAStatus getAudioPorts(
std::vector<::aidl::android::media::audio::common::AudioPort>* _aidl_return) override;
ndk::ScopedAStatus getAudioRoutes(std::vector<AudioRoute>* _aidl_return) override;
+ ndk::ScopedAStatus getAudioRoutesForAudioPort(
+ int32_t in_portId,
+ std::vector<::aidl::android::hardware::audio::core::AudioRoute>* _aidl_return) override;
ndk::ScopedAStatus openInputStream(
int32_t in_portConfigId,
const ::aidl::android::hardware::audio::common::SinkMetadata& in_sinkMetadata,
@@ -63,6 +73,9 @@
void registerPatch(const AudioPatch& patch);
std::unique_ptr<internal::Configuration> mConfig;
+ ModuleDebug mDebug;
+ // 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.
diff --git a/audio/aidl/default/include/core-impl/utils.h b/audio/aidl/default/include/core-impl/utils.h
index 7101012..9d06f08 100644
--- a/audio/aidl/default/include/core-impl/utils.h
+++ b/audio/aidl/default/include/core-impl/utils.h
@@ -38,11 +38,11 @@
return oldSize - c.size();
}
-// Erase all the elements in the map that satisfy the provided predicate.
+// Erase all the elements in the container that satisfy the provided predicate.
template <typename C, typename P>
auto erase_if(C& c, P pred) {
auto oldSize = c.size();
- for (auto it = c.begin(), last = c.end(); it != last;) {
+ for (auto it = c.begin(); it != c.end();) {
if (pred(*it)) {
it = c.erase(it);
} else {
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 3faa39a..3f8d088 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -46,14 +46,16 @@
for (const auto& port : mPorts) {
if (port.ext.getTag() != AudioPortExt::Tag::device) continue;
const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
- const bool isInput = port.flags.getTag() == AudioIoFlags::Tag::input;
if (devicePort.device.type.connection.empty()) {
+ const bool isInput = port.flags.getTag() == AudioIoFlags::Tag::input;
// Permanently attached device.
if (isInput) {
mAttachedSourceDevicePorts.insert(port.id);
} else {
mAttachedSinkDevicePorts.insert(port.id);
}
+ } else if (port.profiles.empty()) {
+ mExternalDevicePorts.insert(port.id);
}
}
if (!mStatus.isOk()) return;
@@ -62,6 +64,22 @@
mStatus = module->getAudioPortConfigs(&mInitialConfigs);
}
+std::vector<AudioPort> ModuleConfig::getAttachedDevicePorts() const {
+ std::vector<AudioPort> result;
+ std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [&](const auto& port) {
+ return mAttachedSinkDevicePorts.count(port.id) != 0 ||
+ mAttachedSourceDevicePorts.count(port.id) != 0;
+ });
+ return result;
+}
+
+std::vector<AudioPort> ModuleConfig::getExternalDevicePorts() const {
+ std::vector<AudioPort> result;
+ std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result),
+ [&](const auto& port) { return mExternalDevicePorts.count(port.id) != 0; });
+ return result;
+}
+
std::vector<AudioPort> ModuleConfig::getInputMixPorts() const {
std::vector<AudioPort> result;
std::copy_if(mPorts.begin(), mPorts.end(), std::back_inserter(result), [](const auto& port) {
@@ -229,6 +247,23 @@
return result;
}
+std::string ModuleConfig::toString() const {
+ std::string result;
+ result.append("Ports: ");
+ result.append(android::internal::ToString(mPorts));
+ result.append("Initial configs: ");
+ result.append(android::internal::ToString(mInitialConfigs));
+ result.append("Attached sink device ports: ");
+ result.append(android::internal::ToString(mAttachedSinkDevicePorts));
+ result.append("Attached source device ports: ");
+ result.append(android::internal::ToString(mAttachedSourceDevicePorts));
+ result.append("External device ports: ");
+ result.append(android::internal::ToString(mExternalDevicePorts));
+ result.append("Routes: ");
+ result.append(android::internal::ToString(mRoutes));
+ return result;
+}
+
static std::vector<AudioPortConfig> combineAudioConfigs(const AudioPort& port,
const AudioProfile& profile) {
std::vector<AudioPortConfig> configs;
@@ -319,10 +354,14 @@
if (singleProfile && !result.empty()) return result;
}
if (resultSizeBefore == result.size()) {
- AudioPortConfig empty;
- empty.portId = devicePort.id;
- empty.ext = devicePort.ext;
- result.push_back(empty);
+ std::copy_if(mInitialConfigs.begin(), mInitialConfigs.end(), std::back_inserter(result),
+ [&](const auto& config) { return config.portId == devicePort.id; });
+ if (resultSizeBefore == result.size()) {
+ AudioPortConfig empty;
+ empty.portId = devicePort.id;
+ empty.ext = devicePort.ext;
+ result.push_back(empty);
+ }
}
if (singleProfile) return result;
}
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index 2e86b97..0e2738b 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -37,6 +37,8 @@
android::binder::Status getStatus() const { return mStatus; }
std::string getError() const { return mStatus.toString8().c_str(); }
+ std::vector<android::media::audio::common::AudioPort> getAttachedDevicePorts() const;
+ std::vector<android::media::audio::common::AudioPort> getExternalDevicePorts() const;
std::vector<android::media::audio::common::AudioPort> getInputMixPorts() const;
std::vector<android::media::audio::common::AudioPort> getOutputMixPorts() const;
std::vector<android::media::audio::common::AudioPort> getMixPorts(bool isInput) const {
@@ -59,6 +61,10 @@
std::optional<SrcSinkPair> getRoutableSrcSinkPair(bool isInput) const;
std::vector<SrcSinkGroup> getRoutableSrcSinkGroups(bool isInput) const;
+ std::vector<android::media::audio::common::AudioPortConfig>
+ getPortConfigsForAttachedDevicePorts() const {
+ return generateAudioDevicePortConfigs(getAttachedDevicePorts(), false);
+ }
std::vector<android::media::audio::common::AudioPortConfig> getPortConfigsForMixPorts() const {
auto inputs = generateInputAudioMixPortConfigs(getInputMixPorts(), false);
auto outputs = generateOutputAudioMixPortConfigs(getOutputMixPorts(), false);
@@ -98,15 +104,18 @@
}
}
+ std::vector<android::media::audio::common::AudioPortConfig> getPortConfigsForDevicePort(
+ const android::media::audio::common::AudioPort& port) const {
+ return generateAudioDevicePortConfigs({port}, false);
+ }
android::media::audio::common::AudioPortConfig getSingleConfigForDevicePort(
const android::media::audio::common::AudioPort& port) const {
- for (const auto& config : mInitialConfigs) {
- if (config.portId == port.id) return config;
- }
const auto config = generateAudioDevicePortConfigs({port}, true);
return *config.begin();
}
+ std::string toString() const;
+
private:
std::vector<android::media::audio::common::AudioPortConfig> generateInputAudioMixPortConfigs(
const std::vector<android::media::audio::common::AudioPort>& ports,
@@ -117,7 +126,8 @@
// Unlike MixPorts, the generator for DevicePorts always returns a non-empty
// vector for a non-empty input port list. If there are no profiles in the
- // port, a vector with an empty config is returned.
+ // port, its initial configs are looked up, if there are none,
+ // then an empty config is used, assuming further negotiation via setAudioPortConfig.
std::vector<android::media::audio::common::AudioPortConfig> generateAudioDevicePortConfigs(
const std::vector<android::media::audio::common::AudioPort>& ports,
bool singleProfile) const;
@@ -127,5 +137,6 @@
std::vector<android::media::audio::common::AudioPortConfig> mInitialConfigs;
std::set<int32_t> mAttachedSinkDevicePorts;
std::set<int32_t> mAttachedSourceDevicePorts;
+ std::set<int32_t> mExternalDevicePorts;
std::vector<android::hardware::audio::core::AudioRoute> mRoutes;
};
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
index cadeb0c..824ac8d 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
@@ -22,6 +22,9 @@
#include <set>
#include <string>
+#define LOG_TAG "VtsHalAudioCore"
+#include <android-base/logging.h>
+
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <android-base/properties.h>
@@ -45,9 +48,12 @@
using android::hardware::audio::core::IModule;
using android::hardware::audio::core::IStreamIn;
using android::hardware::audio::core::IStreamOut;
+using android::hardware::audio::core::ModuleDebug;
using android::media::audio::common::AudioContentType;
using android::media::audio::common::AudioDevice;
+using android::media::audio::common::AudioDeviceAddress;
using android::media::audio::common::AudioDeviceType;
+using android::media::audio::common::AudioFormatType;
using android::media::audio::common::AudioIoFlags;
using android::media::audio::common::AudioOutputFlags;
using android::media::audio::common::AudioPort;
@@ -63,7 +69,7 @@
}
template <typename C>
-std::vector<int32_t> getNonExistentIds(const C& allIds) {
+std::vector<int32_t> GetNonExistentIds(const C& allIds) {
if (allIds.empty()) {
return std::vector<int32_t>{-1, 0, 1};
}
@@ -73,6 +79,12 @@
return nonExistentIds;
}
+AudioDeviceAddress GenerateUniqueDeviceAddress() {
+ static int nextId = 1;
+ // TODO: Use connection-specific ID.
+ return AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>(std::to_string(++nextId));
+}
+
struct AidlDeathRecipient : IBinder::DeathRecipient {
std::mutex mutex;
std::condition_variable condition;
@@ -107,70 +119,28 @@
return false;
}
-class AudioCoreModule : public testing::TestWithParam<std::string> {
+class WithDebugFlags {
public:
- void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); }
-
- void ConnectToService() {
- module = android::waitForDeclaredService<IModule>(String16(GetParam().c_str()));
- ASSERT_NE(module, nullptr);
- }
-
- void RestartService() {
- ASSERT_NE(module, nullptr);
- moduleConfig.reset();
- deathHandler = sp<AidlDeathRecipient>::make();
- ASSERT_EQ(NO_ERROR, IModule::asBinder(module)->linkToDeath(deathHandler));
- ASSERT_TRUE(base::SetProperty("sys.audio.restart.hal", "1"));
- EXPECT_TRUE(deathHandler->waitForFired(3000));
- deathHandler = nullptr;
- ASSERT_NO_FATAL_FAILURE(ConnectToService());
- }
-
- template <typename Entity>
- void GetAllEntityIds(std::set<int32_t>* entityIds,
- Status (IModule::*getter)(std::vector<Entity>*),
- const std::string& errorMessage) {
- std::vector<Entity> entities;
- {
- Status status = (module.get()->*getter)(&entities);
- ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
- }
- std::transform(entities.begin(), entities.end(),
- std::inserter(*entityIds, entityIds->begin()),
- [](const auto& entity) { return entity.id; });
- EXPECT_EQ(entities.size(), entityIds->size()) << errorMessage;
- }
-
- void GetAllPatchIds(std::set<int32_t>* patchIds) {
- return GetAllEntityIds<AudioPatch>(
- patchIds, &IModule::getAudioPatches,
- "IDs of audio patches returned by IModule.getAudioPatches are not unique");
- }
-
- void GetAllPortIds(std::set<int32_t>* portIds) {
- return GetAllEntityIds<AudioPort>(
- portIds, &IModule::getAudioPorts,
- "IDs of audio ports returned by IModule.getAudioPorts are not unique");
- }
-
- void GetAllPortConfigIds(std::set<int32_t>* portConfigIds) {
- return GetAllEntityIds<AudioPortConfig>(
- portConfigIds, &IModule::getAudioPortConfigs,
- "IDs of audio port configs returned by IModule.getAudioPortConfigs are not unique");
- }
-
- void SetUpModuleConfig() {
- if (moduleConfig == nullptr) {
- moduleConfig = std::make_unique<ModuleConfig>(module.get());
- ASSERT_EQ(Status::EX_NONE, moduleConfig->getStatus().exceptionCode())
- << "ModuleConfig init error: " << moduleConfig->getError();
+ WithDebugFlags() {}
+ explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
+ explicit WithDebugFlags(const WithDebugFlags& initial)
+ : mInitial(initial.mFlags), mFlags(initial.mFlags) {}
+ ~WithDebugFlags() {
+ if (mModule != nullptr) {
+ Status status = mModule->setModuleDebug(mInitial);
+ EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
}
}
+ void SetUp(IModule* module) {
+ Status status = module->setModuleDebug(mFlags);
+ ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+ }
+ ModuleDebug& flags() { return mFlags; }
- sp<IModule> module;
- sp<AidlDeathRecipient> deathHandler;
- std::unique_ptr<ModuleConfig> moduleConfig;
+ private:
+ ModuleDebug mInitial;
+ ModuleDebug mFlags;
+ IModule* mModule = nullptr;
};
// For consistency, WithAudioPortConfig can start both with a non-existent
@@ -226,6 +196,147 @@
AudioPortConfig mConfig;
};
+class AudioCoreModule : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(ConnectToService());
+ debug.flags().simulateDeviceConnections = true;
+ ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
+ }
+
+ void TearDown() override {
+ if (module != nullptr) {
+ Status status = module->setModuleDebug(ModuleDebug{});
+ EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+ << status << " returned when resetting debug flags";
+ }
+ }
+
+ void ConnectToService() {
+ module = android::waitForDeclaredService<IModule>(String16(GetParam().c_str()));
+ ASSERT_NE(module, nullptr);
+ }
+
+ void RestartService() {
+ ASSERT_NE(module, nullptr);
+ moduleConfig.reset();
+ deathHandler = sp<AidlDeathRecipient>::make();
+ ASSERT_EQ(NO_ERROR, IModule::asBinder(module)->linkToDeath(deathHandler));
+ ASSERT_TRUE(base::SetProperty("sys.audio.restart.hal", "1"));
+ EXPECT_TRUE(deathHandler->waitForFired(3000));
+ deathHandler = nullptr;
+ ASSERT_NO_FATAL_FAILURE(ConnectToService());
+ }
+
+ void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
+ for (const auto& config : configs) {
+ ASSERT_NE(0, config.portId);
+ WithAudioPortConfig portConfig(config);
+ ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get())); // calls setAudioPortConfig
+ EXPECT_EQ(config.portId, portConfig.get().portId);
+ std::vector<AudioPortConfig> retrievedPortConfigs;
+ Status status = module->getAudioPortConfigs(&retrievedPortConfigs);
+ ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+ const int32_t portConfigId = portConfig.getId();
+ auto configIt = std::find_if(
+ retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
+ [&portConfigId](const auto& retrConf) { return retrConf.id == portConfigId; });
+ EXPECT_NE(configIt, retrievedPortConfigs.end())
+ << "Port config id returned by setAudioPortConfig: " << portConfigId
+ << " is not found in the list returned by getAudioPortConfigs";
+ if (configIt != retrievedPortConfigs.end()) {
+ EXPECT_EQ(portConfig.get(), *configIt)
+ << "Applied port config returned by setAudioPortConfig: "
+ << portConfig.get().toString()
+ << " is not the same as retrieved via getAudioPortConfigs: "
+ << configIt->toString();
+ }
+ }
+ }
+
+ template <typename Entity>
+ void GetAllEntityIds(std::set<int32_t>* entityIds,
+ Status (IModule::*getter)(std::vector<Entity>*),
+ const std::string& errorMessage) {
+ std::vector<Entity> entities;
+ {
+ Status status = (module.get()->*getter)(&entities);
+ ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+ }
+ std::transform(entities.begin(), entities.end(),
+ std::inserter(*entityIds, entityIds->begin()),
+ [](const auto& entity) { return entity.id; });
+ EXPECT_EQ(entities.size(), entityIds->size()) << errorMessage;
+ }
+
+ void GetAllPatchIds(std::set<int32_t>* patchIds) {
+ return GetAllEntityIds<AudioPatch>(
+ patchIds, &IModule::getAudioPatches,
+ "IDs of audio patches returned by IModule.getAudioPatches are not unique");
+ }
+
+ void GetAllPortIds(std::set<int32_t>* portIds) {
+ return GetAllEntityIds<AudioPort>(
+ portIds, &IModule::getAudioPorts,
+ "IDs of audio ports returned by IModule.getAudioPorts are not unique");
+ }
+
+ void GetAllPortConfigIds(std::set<int32_t>* portConfigIds) {
+ return GetAllEntityIds<AudioPortConfig>(
+ portConfigIds, &IModule::getAudioPortConfigs,
+ "IDs of audio port configs returned by IModule.getAudioPortConfigs are not unique");
+ }
+
+ void SetUpModuleConfig() {
+ if (moduleConfig == nullptr) {
+ moduleConfig = std::make_unique<ModuleConfig>(module.get());
+ ASSERT_EQ(Status::EX_NONE, moduleConfig->getStatus().exceptionCode())
+ << "ModuleConfig init error: " << moduleConfig->getError();
+ }
+ }
+
+ sp<IModule> module;
+ sp<AidlDeathRecipient> deathHandler;
+ std::unique_ptr<ModuleConfig> moduleConfig;
+ WithDebugFlags debug;
+};
+
+class WithDevicePortConnectedState {
+ public:
+ explicit WithDevicePortConnectedState(const AudioPort& idAndData) : mIdAndData(idAndData) {}
+ WithDevicePortConnectedState(const AudioPort& id, const AudioDeviceAddress& address)
+ : mIdAndData(setAudioPortAddress(id, address)) {}
+ ~WithDevicePortConnectedState() {
+ if (mModule != nullptr) {
+ Status status = mModule->disconnectExternalDevice(getId());
+ EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+ << status << " returned when disconnecting device port ID " << getId();
+ }
+ }
+ void SetUp(IModule* module) {
+ Status status = module->connectExternalDevice(mIdAndData, &mConnectedPort);
+ ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+ << status << " returned when connecting device port ID & data "
+ << mIdAndData.toString();
+ ASSERT_NE(mIdAndData.id, getId())
+ << "ID of the connected port must not be the same as the ID of the template port";
+ mModule = module;
+ }
+ int32_t getId() const { return mConnectedPort.id; }
+ const AudioPort& get() { return mConnectedPort; }
+
+ private:
+ static AudioPort setAudioPortAddress(const AudioPort& id, const AudioDeviceAddress& address) {
+ AudioPort result = id;
+ result.ext.get<AudioPortExt::Tag::device>().device.address = address;
+ return result;
+ }
+
+ const AudioPort mIdAndData;
+ IModule* mModule = nullptr;
+ AudioPort mConnectedPort;
+};
+
template <typename Stream>
class WithStream {
public:
@@ -332,7 +443,7 @@
ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
}
-TEST_P(AudioCoreModule, GetAudioPortsIsStatic) {
+TEST_P(AudioCoreModule, GetAudioPortsIsStable) {
std::vector<AudioPort> ports1;
{
Status status = module->getAudioPorts(&ports1);
@@ -344,13 +455,13 @@
ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
}
ASSERT_EQ(ports1.size(), ports2.size())
- << "Sizes of audio port arrays do not match across calls to getAudioPorts";
+ << "Sizes of audio port arrays do not match across consequent calls to getAudioPorts";
std::sort(ports1.begin(), ports1.end());
std::sort(ports2.begin(), ports2.end());
EXPECT_EQ(ports1, ports2);
}
-TEST_P(AudioCoreModule, GetAudioRoutesIsStatic) {
+TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
std::vector<AudioRoute> routes1;
{
Status status = module->getAudioRoutes(&routes1);
@@ -362,7 +473,7 @@
ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
}
ASSERT_EQ(routes1.size(), routes2.size())
- << "Sizes of audio route arrays do not match across calls to getAudioRoutes";
+ << "Sizes of audio route arrays do not match across consequent calls to getAudioRoutes";
std::sort(routes1.begin(), routes1.end());
std::sort(routes2.begin(), routes2.end());
EXPECT_EQ(routes1, routes2);
@@ -401,6 +512,32 @@
}
}
+TEST_P(AudioCoreModule, GetAudioRoutesForAudioPort) {
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ if (portIds.empty()) {
+ GTEST_SKIP() << "No ports in the module.";
+ }
+ for (const auto portId : portIds) {
+ std::vector<AudioRoute> routes;
+ Status status = module->getAudioRoutesForAudioPort(portId, &routes);
+ EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+ for (const auto& r : routes) {
+ if (r.sinkPortId != portId) {
+ const auto& srcs = r.sourcePortIds;
+ EXPECT_TRUE(std::find(srcs.begin(), srcs.end(), portId) != srcs.end())
+ << " port ID " << portId << " does not used by the route " << r.toString();
+ }
+ }
+ }
+ for (const auto portId : GetNonExistentIds(portIds)) {
+ std::vector<AudioRoute> routes;
+ Status status = module->getAudioRoutesForAudioPort(portId, &routes);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+ << status << " returned for port ID " << portId;
+ }
+}
+
TEST_P(AudioCoreModule, CheckDevicePorts) {
std::vector<AudioPort> ports;
{
@@ -486,7 +623,7 @@
EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
EXPECT_EQ(portId, port.id);
}
- for (const auto portId : getNonExistentIds(portIds)) {
+ for (const auto portId : GetNonExistentIds(portIds)) {
AudioPort port;
Status status = module->getAudioPort(portId, &port);
EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
@@ -494,10 +631,59 @@
}
}
+// Verify that HAL module reports for a connected device port at least one non-dynamic profile,
+// that is, a profile with actual supported configuration.
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, GetAudioPortWithExternalDevices) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ AudioPort portWithData = port;
+ portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+ GenerateUniqueDeviceAddress();
+ WithDevicePortConnectedState portConnected(portWithData);
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ const int32_t connectedPortId = portConnected.getId();
+ ASSERT_NE(portWithData.id, connectedPortId);
+ ASSERT_EQ(portWithData.ext.getTag(), portConnected.get().ext.getTag());
+ EXPECT_EQ(portWithData.ext.get<AudioPortExt::Tag::device>().device,
+ portConnected.get().ext.get<AudioPortExt::Tag::device>().device);
+ // Verify that 'getAudioPort' and 'getAudioPorts' return the same connected port.
+ AudioPort connectedPort;
+ Status status = module->getAudioPort(connectedPortId, &connectedPort);
+ EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+ << status << " returned for getAudioPort port ID " << connectedPortId;
+ EXPECT_EQ(portConnected.get(), connectedPort);
+ const auto& portProfiles = connectedPort.profiles;
+ EXPECT_NE(0, portProfiles.size())
+ << "Connected port has no profiles: " << connectedPort.toString();
+ const auto dynamicProfileIt =
+ std::find_if(portProfiles.begin(), portProfiles.end(), [](const auto& profile) {
+ return profile.format.type == AudioFormatType::DEFAULT;
+ });
+ EXPECT_EQ(portProfiles.end(), dynamicProfileIt) << "Connected port contains dynamic "
+ << "profiles: " << connectedPort.toString();
+
+ std::vector<AudioPort> allPorts;
+ {
+ Status status = module->getAudioPorts(&allPorts);
+ ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+ }
+ const auto allPortsIt = findById(allPorts, connectedPortId);
+ EXPECT_NE(allPorts.end(), allPortsIt);
+ if (allPortsIt != allPorts.end()) {
+ EXPECT_EQ(portConnected.get(), *allPortsIt);
+ }
+ }
+}
+
TEST_P(AudioCoreModule, OpenStreamInvalidPortConfigId) {
std::set<int32_t> portConfigIds;
ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
- for (const auto portConfigId : getNonExistentIds(portConfigIds)) {
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
{
sp<IStreamIn> stream;
Status status = module->openInputStream(portConfigId, {}, &stream);
@@ -537,7 +723,7 @@
TEST_P(AudioCoreModule, ResetAudioPortConfigInvalidId) {
std::set<int32_t> portConfigIds;
ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
- for (const auto portConfigId : getNonExistentIds(portConfigIds)) {
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
Status status = module->resetAudioPortConfig(portConfigId);
EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
<< status << " returned for port config ID " << portConfigId;
@@ -608,39 +794,35 @@
EXPECT_EQ(suggestedConfig.flags.value(), appliedConfig.flags.value());
}
+TEST_P(AudioCoreModule, SetAllAttachedDevicePortConfigs) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForAttachedDevicePorts()));
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, SetAllExternalDevicePortConfigs) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ ASSERT_NO_FATAL_FAILURE(
+ ApplyEveryConfig(moduleConfig->getPortConfigsForDevicePort(portConnected.get())));
+ }
+}
+
TEST_P(AudioCoreModule, SetAllStaticAudioPortConfigs) {
ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
- const auto allPortConfigs = moduleConfig->getPortConfigsForMixPorts();
- for (const auto& config : allPortConfigs) {
- ASSERT_NE(0, config.portId);
- WithAudioPortConfig portConfig(config);
- ASSERT_NO_FATAL_FAILURE(portConfig.SetUp(module.get()));
- EXPECT_EQ(config.portId, portConfig.get().portId);
- std::vector<AudioPortConfig> retrievedPortConfigs;
- {
- Status status = module->getAudioPortConfigs(&retrievedPortConfigs);
- ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
- }
- const int32_t portConfigId = portConfig.getId();
- auto configIt = std::find_if(
- retrievedPortConfigs.begin(), retrievedPortConfigs.end(),
- [&portConfigId](const auto& retrConf) { return retrConf.id == portConfigId; });
- EXPECT_NE(configIt, retrievedPortConfigs.end())
- << "Port config id returned by setAudioPortConfig: " << portConfigId
- << " is not found in the list returned by getPortConfigsForMixPorts";
- if (configIt != retrievedPortConfigs.end()) {
- EXPECT_EQ(portConfig.get(), *configIt)
- << "Port config returned by getPortConfigsForMixPorts: " << configIt->toString()
- << " is not the same as returned by setAudioPortConfig: "
- << portConfig.get().toString();
- }
- }
+ ASSERT_NO_FATAL_FAILURE(ApplyEveryConfig(moduleConfig->getPortConfigsForMixPorts()));
}
TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortId) {
std::set<int32_t> portIds;
ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
- for (const auto portId : getNonExistentIds(portIds)) {
+ for (const auto portId : GetNonExistentIds(portIds)) {
AudioPortConfig portConfig, suggestedConfig;
bool applied;
portConfig.portId = portId;
@@ -656,7 +838,7 @@
TEST_P(AudioCoreModule, SetAudioPortConfigInvalidPortConfigId) {
std::set<int32_t> portConfigIds;
ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
- for (const auto portConfigId : getNonExistentIds(portConfigIds)) {
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
AudioPortConfig portConfig, suggestedConfig;
bool applied;
portConfig.id = portConfigId;
@@ -669,6 +851,203 @@
}
}
+TEST_P(AudioCoreModule, TryConnectMissingDevice) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ AudioPort ignored;
+ WithDebugFlags doNotSimulateConnections(debug);
+ doNotSimulateConnections.flags().simulateDeviceConnections = false;
+ ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
+ for (const auto& port : ports) {
+ AudioPort portWithData = port;
+ portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+ GenerateUniqueDeviceAddress();
+ Status status = module->connectExternalDevice(portWithData, &ignored);
+ EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+ << status << " returned for static port " << portWithData.toString();
+ }
+}
+
+TEST_P(AudioCoreModule, TryChangingConnectionSimulationMidway) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ WithDevicePortConnectedState portConnected(*ports.begin(), GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ ModuleDebug midwayDebugChange = debug.flags();
+ midwayDebugChange.simulateDeviceConnections = false;
+ Status status = module->setModuleDebug(midwayDebugChange);
+ EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+ << status << " returned when trying to disable connections simulation "
+ << "while having a connected device";
+}
+
+TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceInvalidPorts) {
+ AudioPort ignored;
+ std::set<int32_t> portIds;
+ ASSERT_NO_FATAL_FAILURE(GetAllPortIds(&portIds));
+ for (const auto portId : GetNonExistentIds(portIds)) {
+ AudioPort invalidPort;
+ invalidPort.id = portId;
+ Status status = module->connectExternalDevice(invalidPort, &ignored);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+ << status << " returned for port ID " << portId << " when setting CONNECTED state";
+ status = module->disconnectExternalDevice(portId);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+ << status << " returned for port ID " << portId
+ << " when setting DISCONNECTED state";
+ }
+
+ std::vector<AudioPort> ports;
+ {
+ Status status = module->getAudioPorts(&ports);
+ ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+ }
+ for (const auto& port : ports) {
+ if (port.ext.getTag() != AudioPortExt::Tag::device) {
+ Status status = module->connectExternalDevice(port, &ignored);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+ << status << " returned for non-device port ID " << port.id
+ << " when setting CONNECTED state";
+ status = module->disconnectExternalDevice(port.id);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+ << status << " returned for non-device port ID " << port.id
+ << " when setting DISCONNECTED state";
+ } else {
+ const auto& devicePort = port.ext.get<AudioPortExt::Tag::device>();
+ if (devicePort.device.type.connection.empty()) {
+ Status status = module->connectExternalDevice(port, &ignored);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+ << status << " returned for permanently attached device port ID " << port.id
+ << " when setting CONNECTED state";
+ status = module->disconnectExternalDevice(port.id);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+ << status << " returned for permanently attached device port ID " << port.id
+ << " when setting DISCONNECTED state";
+ }
+ }
+ }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, ConnectDisconnectExternalDeviceTwice) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ AudioPort ignored;
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ Status status = module->disconnectExternalDevice(port.id);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+ << status << " returned when disconnecting already disconnected device port ID "
+ << port.id;
+ AudioPort portWithData = port;
+ portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+ GenerateUniqueDeviceAddress();
+ WithDevicePortConnectedState portConnected(portWithData);
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ status = module->connectExternalDevice(portConnected.get(), &ignored);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+ << status << " returned when trying to connect a connected device port "
+ << portConnected.get().toString();
+ status = module->connectExternalDevice(portWithData, &ignored);
+ EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+ << status << " returned when connecting again the external device "
+ << portWithData.ext.get<AudioPortExt::Tag::device>().device.toString();
+ if (status.exceptionCode() == Status::EX_NONE) {
+ ADD_FAILURE() << "Returned connected port " << ignored.toString() << " for template "
+ << portWithData.toString();
+ }
+ }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, DisconnectExternalDeviceNonResetPortConfig) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ const auto portConfig = moduleConfig->getSingleConfigForDevicePort(portConnected.get());
+ {
+ WithAudioPortConfig config(portConfig);
+ // Note: if SetUp fails, check the status of 'GetAudioPortWithExternalDevices' test.
+ // Our test assumes that 'getAudioPort' returns at least one profile, and it
+ // is not a dynamic profile.
+ ASSERT_NO_FATAL_FAILURE(config.SetUp(module.get()));
+ Status status = module->disconnectExternalDevice(portConnected.getId());
+ EXPECT_EQ(Status::EX_ILLEGAL_STATE, status.exceptionCode())
+ << status << " returned when trying to disconnect device port ID " << port.id
+ << " with active configuration " << config.getId();
+ }
+ }
+}
+
+TEST_P(AudioCoreModule, ExternalDevicePortRoutes) {
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> ports = moduleConfig->getExternalDevicePorts();
+ if (ports.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : ports) {
+ std::vector<AudioRoute> routesBefore;
+ {
+ Status status = module->getAudioRoutes(&routesBefore);
+ ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+ }
+
+ int32_t connectedPortId;
+ {
+ WithDevicePortConnectedState portConnected(port, GenerateUniqueDeviceAddress());
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
+ connectedPortId = portConnected.getId();
+ std::vector<AudioRoute> connectedPortRoutes;
+ {
+ Status status =
+ module->getAudioRoutesForAudioPort(connectedPortId, &connectedPortRoutes);
+ ASSERT_EQ(Status::EX_NONE, status.exceptionCode())
+ << status << " returned when retrieving routes for connected port id "
+ << connectedPortId;
+ }
+ // There must be routes for the port to be useful.
+ if (connectedPortRoutes.empty()) {
+ std::vector<AudioRoute> allRoutes;
+ Status status = module->getAudioRoutes(&allRoutes);
+ ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+ ADD_FAILURE() << " no routes returned for the connected port "
+ << portConnected.get().toString()
+ << "; all routes: " << android::internal::ToString(allRoutes);
+ }
+ }
+ std::vector<AudioRoute> ignored;
+ Status status = module->getAudioRoutesForAudioPort(connectedPortId, &ignored);
+ ASSERT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
+ << status << " returned when retrieving routes for released connected port id "
+ << connectedPortId;
+
+ std::vector<AudioRoute> routesAfter;
+ {
+ Status status = module->getAudioRoutes(&routesAfter);
+ ASSERT_EQ(Status::EX_NONE, status.exceptionCode()) << status;
+ }
+ ASSERT_EQ(routesBefore.size(), routesAfter.size())
+ << "Sizes of audio route arrays do not match after creating and "
+ << "releasing a connected port";
+ std::sort(routesBefore.begin(), routesBefore.end());
+ std::sort(routesAfter.begin(), routesAfter.end());
+ EXPECT_EQ(routesBefore, routesAfter);
+ }
+}
+
template <typename Stream>
class AudioStream : public AudioCoreModule {
public:
@@ -899,7 +1278,7 @@
std::set<int32_t> portConfigIds;
ASSERT_NO_FATAL_FAILURE(GetAllPortConfigIds(&portConfigIds));
- for (const auto portConfigId : getNonExistentIds(portConfigIds)) {
+ for (const auto portConfigId : GetNonExistentIds(portConfigIds)) {
EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(
Status::EX_ILLEGAL_ARGUMENT, {portConfigId}, {sinkPortConfig.getId()}));
EXPECT_NO_FATAL_FAILURE(SetInvalidPatchHelper(Status::EX_ILLEGAL_ARGUMENT,
@@ -969,7 +1348,7 @@
// Then use the same patch setting, except for having an invalid ID.
std::set<int32_t> patchIds;
ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
- for (const auto patchId : getNonExistentIds(patchIds)) {
+ for (const auto patchId : GetNonExistentIds(patchIds)) {
AudioPatch patchWithNonExistendId = patch.get();
patchWithNonExistendId.id = patchId;
Status status = module->setAudioPatch(patchWithNonExistendId, &patchWithNonExistendId);
@@ -995,7 +1374,7 @@
TEST_P(AudioModulePatch, ResetInvalidPatchId) {
std::set<int32_t> patchIds;
ASSERT_NO_FATAL_FAILURE(GetAllPatchIds(&patchIds));
- for (const auto patchId : getNonExistentIds(patchIds)) {
+ for (const auto patchId : GetNonExistentIds(patchIds)) {
Status status = module->resetAudioPatch(patchId);
EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, status.exceptionCode())
<< status << " returned for patch ID " << patchId;
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
index d35792d..f01444e 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/tests/DefaultVhalImpl_test.cpp
@@ -402,7 +402,7 @@
gotValue->timestamp = 0;
std::string infoMake = toString(*gotValue);
- EXPECT_THAT(std::string(buf), HasSubstr(infoMake));
+ EXPECT_THAT(std::string(buf, sizeof(buf)), HasSubstr(infoMake));
}
TEST_F(DefaultVhalImplTest, testSetPropInvalidAreaId) {
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash
index 7bb15e8..f478504 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash
@@ -1 +1 @@
-38469e5a0359c95015bea304c463b686cf4ee9ca
+8610b651e162c614a97542d6f4ed039c969823e5
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
index 7e48eba..d7b874a 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
@@ -36,5 +36,5 @@
enum VehicleApPowerStateConfigFlag {
ENABLE_DEEP_SLEEP_FLAG = 1,
CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 2,
- ENABLE_HIBERNATION_FLAG = 3,
+ ENABLE_HIBERNATION_FLAG = 4,
}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
index 7e48eba..d7b874a 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
@@ -36,5 +36,5 @@
enum VehicleApPowerStateConfigFlag {
ENABLE_DEEP_SLEEP_FLAG = 1,
CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 2,
- ENABLE_HIBERNATION_FLAG = 3,
+ ENABLE_HIBERNATION_FLAG = 4,
}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
index 4d8e2f5..8b0190ce 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
@@ -37,5 +37,5 @@
* (via VehicleApPowerStateShutdownParam#CAN_HIBERNATE or
* VehicleApPowerStateShutdownParam#HIBERNATE_IMMEDIATELY flags)
*/
- ENABLE_HIBERNATION_FLAG = 0x3,
+ ENABLE_HIBERNATION_FLAG = 0x4,
}
diff --git a/biometrics/common/thread/Android.bp b/biometrics/common/thread/Android.bp
new file mode 100644
index 0000000..a497d01
--- /dev/null
+++ b/biometrics/common/thread/Android.bp
@@ -0,0 +1,26 @@
+cc_library {
+ // 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
+ name: "android.hardware.biometrics.common.thread",
+ export_include_dirs: ["include"],
+ vendor: true,
+ srcs: [
+ "WorkerThread.cpp",
+ ],
+}
+
+cc_test_host {
+ name: "android.hardware.biometrics.common.WorkerThreadTest",
+ local_include_dirs: ["include"],
+ srcs: [
+ "tests/WorkerThreadTest.cpp",
+ "WorkerThread.cpp",
+ ],
+ shared_libs: [
+ "libcutils",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/biometrics/fingerprint/aidl/default/WorkerThread.cpp b/biometrics/common/thread/WorkerThread.cpp
similarity index 92%
rename from biometrics/fingerprint/aidl/default/WorkerThread.cpp
rename to biometrics/common/thread/WorkerThread.cpp
index 34ebb5c..61d1a13 100644
--- a/biometrics/fingerprint/aidl/default/WorkerThread.cpp
+++ b/biometrics/common/thread/WorkerThread.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#include "WorkerThread.h"
+#include "thread/WorkerThread.h"
-namespace aidl::android::hardware::biometrics::fingerprint {
+namespace aidl::android::hardware::biometrics {
// It's important that mThread is initialized after everything else because it runs a member
// function that may use any member of this class.
@@ -68,4 +68,4 @@
}
}
-} // namespace aidl::android::hardware::biometrics::fingerprint
+} // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/fingerprint/aidl/default/include/Callable.h b/biometrics/common/thread/include/thread/Callable.h
similarity index 92%
rename from biometrics/fingerprint/aidl/default/include/Callable.h
rename to biometrics/common/thread/include/thread/Callable.h
index c629511..6eeff76 100644
--- a/biometrics/fingerprint/aidl/default/include/Callable.h
+++ b/biometrics/common/thread/include/thread/Callable.h
@@ -16,7 +16,7 @@
#pragma once
-namespace aidl::android::hardware::biometrics::fingerprint {
+namespace aidl::android::hardware::biometrics {
// Interface for representing parameterless functions. Unlike std::function<void()>, this can also
// represent move-only lambdas.
@@ -51,4 +51,4 @@
return std::make_unique<AnyFuncWrapper<T>>(std::move(func));
}
-} // namespace aidl::android::hardware::biometrics::fingerprint
\ No newline at end of file
+} // namespace aidl::android::hardware::biometrics
\ No newline at end of file
diff --git a/biometrics/fingerprint/aidl/default/include/WorkerThread.h b/biometrics/common/thread/include/thread/WorkerThread.h
similarity index 95%
rename from biometrics/fingerprint/aidl/default/include/WorkerThread.h
rename to biometrics/common/thread/include/thread/WorkerThread.h
index 6fff4f2..5f89a7f 100644
--- a/biometrics/fingerprint/aidl/default/include/WorkerThread.h
+++ b/biometrics/common/thread/include/thread/WorkerThread.h
@@ -23,7 +23,7 @@
#include "Callable.h"
-namespace aidl::android::hardware::biometrics::fingerprint {
+namespace aidl::android::hardware::biometrics {
// A class that encapsulates a worker thread and a task queue, and provides a convenient interface
// for a Session to schedule its tasks for asynchronous execution.
@@ -76,4 +76,4 @@
std::thread mThread;
};
-} // namespace aidl::android::hardware::biometrics::fingerprint
+} // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp b/biometrics/common/thread/tests/WorkerThreadTest.cpp
similarity index 96%
rename from biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
rename to biometrics/common/thread/tests/WorkerThreadTest.cpp
index 902fb40..5bb9e7e 100644
--- a/biometrics/fingerprint/aidl/default/tests/WorkerThreadTest.cpp
+++ b/biometrics/common/thread/tests/WorkerThreadTest.cpp
@@ -21,12 +21,11 @@
#include <gtest/gtest.h>
-#include "WorkerThread.h"
+#include "thread/WorkerThread.h"
namespace {
-using aidl::android::hardware::biometrics::fingerprint::Callable;
-using aidl::android::hardware::biometrics::fingerprint::WorkerThread;
+using namespace aidl::android::hardware::biometrics;
using namespace std::chrono_literals;
TEST(WorkerThreadTest, ScheduleReturnsTrueWhenQueueHasSpace) {
diff --git a/biometrics/common/util/Android.bp b/biometrics/common/util/Android.bp
new file mode 100644
index 0000000..918ef72
--- /dev/null
+++ b/biometrics/common/util/Android.bp
@@ -0,0 +1,18 @@
+cc_library {
+ // 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
+ name: "android.hardware.biometrics.common.util",
+ export_include_dirs: ["include"],
+ vendor: true,
+ srcs: [
+ "CancellationSignal.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.biometrics.common-V2-ndk",
+ ],
+}
diff --git a/biometrics/fingerprint/aidl/default/CancellationSignal.cpp b/biometrics/common/util/CancellationSignal.cpp
similarity index 87%
rename from biometrics/fingerprint/aidl/default/CancellationSignal.cpp
rename to biometrics/common/util/CancellationSignal.cpp
index 6598316..7888838 100644
--- a/biometrics/fingerprint/aidl/default/CancellationSignal.cpp
+++ b/biometrics/common/util/CancellationSignal.cpp
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#include "CancellationSignal.h"
+#include "util/CancellationSignal.h"
#include <android-base/logging.h>
#include <chrono>
-namespace aidl::android::hardware::biometrics::fingerprint {
+namespace aidl::android::hardware::biometrics {
CancellationSignal::CancellationSignal(std::promise<void>&& cancellationPromise)
: mCancellationPromise(std::move(cancellationPromise)) {}
@@ -34,4 +34,4 @@
return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
-} // namespace aidl::android::hardware::biometrics::fingerprint
+} // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/fingerprint/aidl/default/include/CancellationSignal.h b/biometrics/common/util/include/util/CancellationSignal.h
similarity index 83%
rename from biometrics/fingerprint/aidl/default/include/CancellationSignal.h
rename to biometrics/common/util/include/util/CancellationSignal.h
index 99f2fba..be77e29 100644
--- a/biometrics/fingerprint/aidl/default/include/CancellationSignal.h
+++ b/biometrics/common/util/include/util/CancellationSignal.h
@@ -17,13 +17,10 @@
#pragma once
#include <aidl/android/hardware/biometrics/common/BnCancellationSignal.h>
-#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
#include <functional>
#include <future>
-#include "WorkerThread.h"
-
-namespace aidl::android::hardware::biometrics::fingerprint {
+namespace aidl::android::hardware::biometrics {
class CancellationSignal : public common::BnCancellationSignal {
public:
@@ -39,4 +36,4 @@
// to this future should be cancelled.
bool shouldCancel(const std::future<void>& cancellationFuture);
-} // namespace aidl::android::hardware::biometrics::fingerprint
+} // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/common/util/include/util/Util.h b/biometrics/common/util/include/util/Util.h
new file mode 100644
index 0000000..29ec0f8
--- /dev/null
+++ b/biometrics/common/util/include/util/Util.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+
+#include <chrono>
+#include <regex>
+#include <thread>
+#include <vector>
+
+namespace aidl::android::hardware::biometrics {
+
+#define SLEEP_MS(x) \
+ if (x > 0) std::this_thread::sleep_for(std::chrono::milliseconds(x))
+#define BEGIN_OP(x) \
+ do { \
+ LOG(INFO) << __func__; \
+ SLEEP_MS(x); \
+ } while (0)
+#define IS_TRUE(x) ((x == "1") || (x == "true"))
+
+// This is for non-test situations, such as casual cuttlefish users, that don't
+// set an explicit value.
+// Some operations (i.e. enroll, authenticate) will be executed in tight loops
+// 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
+
+class Util {
+ public:
+ static int64_t getSystemNanoTime() {
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return now.tv_sec * 1000000000LL + now.tv_nsec;
+ }
+
+ static bool hasElapsed(int64_t start, int64_t durationMillis) {
+ auto now = getSystemNanoTime();
+ if (now < start) return true;
+ if (durationMillis <= 0) return true;
+ return ((now - start) / 1000000LL) > durationMillis;
+ }
+
+ static std::vector<std::string> split(const std::string& str, const std::string& sep) {
+ std::regex regex(sep);
+ std::vector<std::string> parts(
+ std::sregex_token_iterator(str.begin(), str.end(), regex, -1),
+ std::sregex_token_iterator());
+ return parts;
+ }
+};
+
+} // namespace aidl::android::hardware::biometrics
\ No newline at end of file
diff --git a/biometrics/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
index 7f66eca..48c929b 100644
--- a/biometrics/face/aidl/default/Android.bp
+++ b/biometrics/face/aidl/default/Android.bp
@@ -18,10 +18,43 @@
"libbinder_ndk",
"android.hardware.biometrics.face-V2-ndk",
"android.hardware.biometrics.common-V2-ndk",
+ "android.hardware.biometrics.common.thread",
+ "android.hardware.biometrics.common.util",
],
srcs: [
"main.cpp",
"Face.cpp",
+ "FakeFaceEngine.cpp",
"Session.cpp",
],
+ static_libs: ["android.hardware.biometrics.face.VirtualProps"],
+}
+
+sysprop_library {
+ name: "android.hardware.biometrics.face.VirtualProps",
+ srcs: ["face.sysprop"],
+ property_owner: "Vendor",
+ vendor: true,
+}
+
+cc_test {
+ name: "android.hardware.biometrics.face.FakeFaceEngineTest",
+ srcs: [
+ "tests/FakeFaceEngineTest.cpp",
+ "FakeFaceEngine.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ ],
+ static_libs: [
+ "android.hardware.biometrics.face.VirtualProps",
+ "android.hardware.biometrics.face-V2-ndk",
+ "android.hardware.biometrics.common-V2-ndk",
+ "android.hardware.keymaster-V3-ndk",
+ "android.hardware.biometrics.common.util",
+ ],
+ vendor: true,
+ test_suites: ["general-tests"],
+ require_root: true,
}
diff --git a/biometrics/face/aidl/default/Face.cpp b/biometrics/face/aidl/default/Face.cpp
index aca3e13..652a7e1 100644
--- a/biometrics/face/aidl/default/Face.cpp
+++ b/biometrics/face/aidl/default/Face.cpp
@@ -17,12 +17,14 @@
#include "Face.h"
#include "Session.h"
+#include "FakeFaceEngine.h"
+
namespace aidl::android::hardware::biometrics::face {
const int kSensorId = 4;
-const common::SensorStrength kSensorStrength = common::SensorStrength::STRONG;
+const common::SensorStrength kSensorStrength = FakeFaceEngine::GetSensorStrength();
const int kMaxEnrollmentsPerUser = 5;
-const FaceSensorType kSensorType = FaceSensorType::RGB;
+const FaceSensorType kSensorType = FakeFaceEngine::GetSensorType();
const bool kHalControlsPreview = true;
const std::string kHwComponentId = "faceSensor";
const std::string kHardwareVersion = "vendor/model/revision";
@@ -69,7 +71,7 @@
ndk::ScopedAStatus Face::createSession(int32_t /*sensorId*/, int32_t /*userId*/,
const std::shared_ptr<ISessionCallback>& cb,
std::shared_ptr<ISession>* return_val) {
- *return_val = SharedRefBase::make<Session>(cb);
+ *return_val = SharedRefBase::make<Session>(std::make_unique<FakeFaceEngine>(), cb);
return ndk::ScopedAStatus::ok();
}
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.cpp b/biometrics/face/aidl/default/FakeFaceEngine.cpp
new file mode 100644
index 0000000..0f088f4
--- /dev/null
+++ b/biometrics/face/aidl/default/FakeFaceEngine.cpp
@@ -0,0 +1,318 @@
+#include "FakeFaceEngine.h"
+
+#include <android-base/logging.h>
+
+#include <face.sysprop.h>
+
+#include "util/CancellationSignal.h"
+#include "util/Util.h"
+
+using namespace ::android::face::virt;
+
+namespace aidl::android::hardware::biometrics::face {
+
+FaceSensorType FakeFaceEngine::GetSensorType() {
+ std::string type = FaceHalProperties::type().value_or("");
+ if (type == "IR") {
+ return FaceSensorType::IR;
+ } else {
+ FaceHalProperties::type("RGB");
+ return FaceSensorType::RGB;
+ }
+}
+
+common::SensorStrength FakeFaceEngine::GetSensorStrength() {
+ std::string strength = FaceHalProperties::strength().value_or("");
+ if (strength == "convenience") {
+ return common::SensorStrength::CONVENIENCE;
+ } else if (strength == "weak") {
+ return common::SensorStrength::WEAK;
+ } else {
+ FaceHalProperties::strength("strong");
+ return common::SensorStrength::STRONG;
+ }
+}
+
+void FakeFaceEngine::generateChallengeImpl(ISessionCallback* cb) {
+ BEGIN_OP(0);
+ std::uniform_int_distribution<int64_t> dist;
+ auto challenge = dist(mRandom);
+ FaceHalProperties::challenge(challenge);
+ cb->onChallengeGenerated(challenge);
+}
+
+void FakeFaceEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
+ BEGIN_OP(0);
+ FaceHalProperties::challenge({});
+ cb->onChallengeRevoked(challenge);
+}
+void FakeFaceEngine::getEnrollmentConfigImpl(ISessionCallback* /*cb*/,
+ std::vector<EnrollmentStageConfig>* /*return_val*/) {}
+void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+ EnrollmentType /*enrollmentType*/,
+ const std::vector<Feature>& /*features*/,
+ const std::future<void>& cancel) {
+ BEGIN_OP(FaceHalProperties::operation_start_enroll_latency().value_or(0));
+ // format is "<id>,<bucket_id>:<delay>:<succeeds>,<bucket_id>:<delay>:<succeeds>...
+ auto nextEnroll = FaceHalProperties::next_enrollment().value_or("");
+ // Erase the next enrollment
+ FaceHalProperties::next_enrollment({});
+
+ AuthenticationFrame frame;
+ frame.data.acquiredInfo = AcquiredInfo::START;
+ frame.data.vendorCode = 0;
+ cb->onAuthenticationFrame(frame);
+
+ // Do proper HAT verification in the real implementation.
+ if (hat.mac.empty()) {
+ LOG(ERROR) << "Fail: hat";
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+ return;
+ }
+
+ if (FaceHalProperties::operation_enroll_fails().value_or(false)) {
+ LOG(ERROR) << "Fail: operation_enroll_fails";
+ cb->onError(Error::VENDOR, 0 /* vendorError */);
+ return;
+ }
+
+ auto parts = Util::split(nextEnroll, ",");
+ if (parts.size() < 2) {
+ LOG(ERROR) << "Fail: invalid next_enrollment for : " << nextEnroll;
+ cb->onError(Error::VENDOR, 0 /* vendorError */);
+ return;
+ }
+
+ auto enrollmentId = std::stoi(parts[0]);
+ const int numBuckets = parts.size() - 1;
+ for (size_t i = 1; i < parts.size(); i++) {
+ auto enrollHit = Util::split(parts[i], ":");
+ if (enrollHit.size() != 3) {
+ LOG(ERROR) << "Error when unpacking enrollment hit: " << parts[i];
+ cb->onError(Error::VENDOR, 0 /* vendorError */);
+ }
+ std::string bucket = enrollHit[0];
+ std::string delay = enrollHit[1];
+ std::string succeeds = enrollHit[2];
+
+ SLEEP_MS(std::stoi(delay));
+
+ if (shouldCancel(cancel)) {
+ LOG(ERROR) << "Fail: cancel";
+ cb->onError(Error::CANCELED, 0 /* vendorCode */);
+ return;
+ }
+
+ if (!IS_TRUE(succeeds)) { // end and failed
+ LOG(ERROR) << "Fail: requested by caller: " << parts[i];
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return;
+ }
+
+ EnrollmentFrame frame;
+
+ frame.data.acquiredInfo = AcquiredInfo::GOOD;
+ frame.data.vendorCode = 0;
+ cb->onEnrollmentFrame(frame);
+
+ frame.data.acquiredInfo = AcquiredInfo::VENDOR;
+ frame.data.vendorCode = std::stoi(bucket);
+ cb->onEnrollmentFrame(frame);
+
+ int remainingBuckets = numBuckets - i;
+ if (remainingBuckets > 0) {
+ cb->onEnrollmentProgress(enrollmentId, remainingBuckets);
+ }
+ }
+
+ auto enrollments = FaceHalProperties::enrollments();
+ enrollments.push_back(enrollmentId);
+ FaceHalProperties::enrollments(enrollments);
+ LOG(INFO) << "enrolled : " << enrollmentId;
+ cb->onEnrollmentProgress(enrollmentId, 0);
+}
+
+void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/,
+ const std::future<void>& cancel) {
+ BEGIN_OP(FaceHalProperties::operation_authenticate_latency().value_or(0));
+
+ // Signal to the framework that we have begun authenticating.
+ AuthenticationFrame frame;
+ frame.data.acquiredInfo = AcquiredInfo::START;
+ frame.data.vendorCode = 0;
+ cb->onAuthenticationFrame(frame);
+
+ // Also signal that we have opened the camera.
+ frame = {};
+ frame.data.acquiredInfo = AcquiredInfo::FIRST_FRAME_RECEIVED;
+ frame.data.vendorCode = 0;
+ cb->onAuthenticationFrame(frame);
+
+ auto now = Util::getSystemNanoTime();
+ int64_t duration = FaceHalProperties::operation_authenticate_duration().value_or(0);
+ if (duration > 0) {
+ do {
+ SLEEP_MS(5);
+ } while (!Util::hasElapsed(now, duration));
+ }
+
+ if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
+ LOG(ERROR) << "Fail: operation_authenticate_fails";
+ cb->onError(Error::VENDOR, 0 /* vendorError */);
+ return;
+ }
+
+ if (FaceHalProperties::lockout().value_or(false)) {
+ LOG(ERROR) << "Fail: lockout";
+ cb->onLockoutPermanent();
+ cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
+ return;
+ }
+
+ if (shouldCancel(cancel)) {
+ LOG(ERROR) << "Fail: cancel";
+ cb->onError(Error::CANCELED, 0 /* vendorCode */);
+ return;
+ }
+
+ auto id = FaceHalProperties::enrollment_hit().value_or(0);
+ auto enrolls = FaceHalProperties::enrollments();
+ auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
+ if (id < 0 || !isEnrolled) {
+ LOG(ERROR) << (isEnrolled ? "invalid enrollment hit" : "Fail: not enrolled");
+ cb->onAuthenticationFailed();
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+ return;
+ }
+
+ cb->onAuthenticationSucceeded(id, {} /* hat */);
+}
+
+void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
+ BEGIN_OP(FaceHalProperties::operation_detect_interaction_latency().value_or(0));
+
+ if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) {
+ LOG(ERROR) << "Fail: operation_detect_interaction_fails";
+ cb->onError(Error::VENDOR, 0 /* vendorError */);
+ return;
+ }
+
+ if (shouldCancel(cancel)) {
+ LOG(ERROR) << "Fail: cancel";
+ cb->onError(Error::CANCELED, 0 /* vendorCode */);
+ return;
+ }
+
+ auto id = FaceHalProperties::enrollment_hit().value_or(0);
+ auto enrolls = FaceHalProperties::enrollments();
+ auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
+ if (id <= 0 || !isEnrolled) {
+ LOG(ERROR) << "Fail: not enrolled";
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
+ return;
+ }
+
+ cb->onInteractionDetected();
+}
+
+void FakeFaceEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
+ BEGIN_OP(0);
+ std::vector<int32_t> enrollments;
+ for (const auto& enrollmentId : FaceHalProperties::enrollments()) {
+ if (enrollmentId) {
+ enrollments.push_back(*enrollmentId);
+ }
+ }
+ cb->onEnrollmentsEnumerated(enrollments);
+}
+
+void FakeFaceEngine::removeEnrollmentsImpl(ISessionCallback* cb,
+ const std::vector<int32_t>& enrollmentIds) {
+ BEGIN_OP(0);
+
+ std::vector<std::optional<int32_t>> newEnrollments;
+ for (const auto& enrollment : FaceHalProperties::enrollments()) {
+ auto id = enrollment.value_or(0);
+ if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) == enrollmentIds.end()) {
+ newEnrollments.emplace_back(id);
+ }
+ }
+ FaceHalProperties::enrollments(newEnrollments);
+ cb->onEnrollmentsRemoved(enrollmentIds);
+}
+
+void FakeFaceEngine::getFeaturesImpl(ISessionCallback* cb) {
+ BEGIN_OP(0);
+
+ if (FaceHalProperties::enrollments().empty()) {
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return;
+ }
+
+ std::vector<Feature> featuresToReturn = {};
+ for (const auto& feature : FaceHalProperties::features()) {
+ if (feature) {
+ featuresToReturn.push_back((Feature)(*feature));
+ }
+ }
+ cb->onFeaturesRetrieved(featuresToReturn);
+}
+
+void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+ Feature feature, bool enabled) {
+ BEGIN_OP(0);
+
+ if (FaceHalProperties::enrollments().empty()) {
+ LOG(ERROR) << "Unable to set feature, enrollments are empty";
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return;
+ }
+
+ if (hat.mac.empty()) {
+ LOG(ERROR) << "Unable to set feature, invalid hat";
+ cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
+ return;
+ }
+
+ auto features = FaceHalProperties::features();
+
+ auto itr = std::find_if(features.begin(), features.end(), [feature](const auto& theFeature) {
+ return *theFeature == (int)feature;
+ });
+
+ if (!enabled && (itr != features.end())) {
+ features.erase(itr);
+ } else if (enabled && (itr == features.end())) {
+ features.push_back((int)feature);
+ }
+
+ FaceHalProperties::features(features);
+ cb->onFeatureSet(feature);
+}
+
+void FakeFaceEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
+ BEGIN_OP(0);
+ // If this is a weak HAL return 0 per the spec.
+ if (GetSensorStrength() != common::SensorStrength::STRONG) {
+ cb->onAuthenticatorIdRetrieved(0);
+ } else {
+ cb->onAuthenticatorIdRetrieved(FaceHalProperties::authenticator_id().value_or(0));
+ }
+}
+
+void FakeFaceEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
+ BEGIN_OP(0);
+ int64_t authenticatorId = FaceHalProperties::authenticator_id().value_or(0);
+ int64_t newId = authenticatorId + 1;
+ FaceHalProperties::authenticator_id(newId);
+ cb->onAuthenticatorIdInvalidated(newId);
+}
+
+void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb,
+ const keymaster::HardwareAuthToken& /*hat*/) {
+ BEGIN_OP(0);
+ FaceHalProperties::lockout(false);
+ cb->onLockoutCleared();
+}
+
+} // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.h b/biometrics/face/aidl/default/FakeFaceEngine.h
new file mode 100644
index 0000000..edb54ce
--- /dev/null
+++ b/biometrics/face/aidl/default/FakeFaceEngine.h
@@ -0,0 +1,65 @@
+/*
+ * 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/biometrics/common/SensorStrength.h>
+#include <aidl/android/hardware/biometrics/face/BnSession.h>
+#include <aidl/android/hardware/biometrics/face/FaceSensorType.h>
+#include <aidl/android/hardware/biometrics/face/ISessionCallback.h>
+
+#include <random>
+
+#include <future>
+#include <vector>
+
+namespace aidl::android::hardware::biometrics::face {
+
+namespace face = aidl::android::hardware::biometrics::face;
+namespace common = aidl::android::hardware::biometrics::common;
+namespace keymaster = aidl::android::hardware::keymaster;
+
+using aidl::android::hardware::common::NativeHandle;
+// A fake engine that is backed by system properties instead of hardware.
+class FakeFaceEngine {
+ public:
+ FakeFaceEngine() : mRandom(std::mt19937::default_seed) {}
+
+ static face::FaceSensorType GetSensorType();
+ static common::SensorStrength GetSensorStrength();
+ void generateChallengeImpl(ISessionCallback* cb);
+ void revokeChallengeImpl(ISessionCallback* cb, int64_t challenge);
+ void getEnrollmentConfigImpl(ISessionCallback* cb,
+ std::vector<EnrollmentStageConfig>* return_val);
+ void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+ EnrollmentType enrollmentType, const std::vector<Feature>& features,
+ 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);
+ void enumerateEnrollmentsImpl(ISessionCallback* cb);
+ void removeEnrollmentsImpl(ISessionCallback* cb, const std::vector<int32_t>& enrollmentIds);
+ void getFeaturesImpl(ISessionCallback* cb);
+ void setFeatureImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+ Feature feature, bool enabled);
+ void getAuthenticatorIdImpl(ISessionCallback* cb);
+ void invalidateAuthenticatorIdImpl(ISessionCallback* cb);
+ void resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/);
+
+ std::mt19937 mRandom;
+};
+
+} // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
diff --git a/biometrics/face/aidl/default/README.md b/biometrics/face/aidl/default/README.md
new file mode 100644
index 0000000..1655973
--- /dev/null
+++ b/biometrics/face/aidl/default/README.md
@@ -0,0 +1,77 @@
+# Virtual Face HAL
+
+This is a virtual HAL implementation that is backed by system properties
+instead of actual hardware. It's intended for testing and UI development
+on debuggable builds to allow devices to masquerade as alternative device
+types and for emulators.
+
+## Device Selection
+
+You can either run the FakeFaceEngine on a [real device](#actual-device) or a [virtual device/cuttlefish](#getting-started-on-a-virtual-device-cuttlefish). This document should
+help you to get started on either one.
+
+After setting up a device, go ahead and try out [enrolling](#enrolling) & [authenticating](#authenticating)
+
+### Getting started on a Virtual Device (cuttlefish)
+
+
+Note, I'm running this via a cloudtop virtual device.
+
+1. Setup cuttlefish on cloudtop, See [this](https://g3doc.corp.google.com/company/teams/android/teampages/acloud/getting_started.md?cl=head) for more details.
+2. acloud create --local-image
+3. Enter in the shell command to disable hidl
+
+```shell
+$ adb root
+$ adb shell settings put secure com.android.server.biometrics.AuthService.hidlDisabled 1
+$ adb reboot
+```
+4. You should now be able to do fake enrollments and authentications (as seen down below)
+
+### Actual Device
+
+1. Modify your real devices make file (I.E. vendor/google/products/{YOUR_DEVICE}.mk)
+2. Ensure that there is no other face HAL that is being included by the device
+3. Add the following
+```
+PRODUCT_COPY_FILES += \
+ frameworks/native/data/etc/android.hardware.biometrics.face.xml:$(TARGET_COPY_OUT_PRODUCT)/etc/permissions/android.hardware.biometrics.face.xml
+
+PRODUCT_PACKAGES += \
+ android.hardware.biometrics.face-service.example \
+
+```
+4. Now build and flash m -j120 && flash
+5. Run the following commands
+
+```shell
+# This is a temporary workaround
+$ adb root
+$ adb shell setprop persist.vendor.face.virtual.type RGB
+$ adb shell setprop persist.vendor.face.virtual.strength strong
+$ adb shell locksettings set-pin 0000
+$ adb reboot
+```
+
+## Enrolling
+
+```shell
+# authenticar_id,bucket_id:duration:(true|false)....
+$ adb shell setprop vendor.face.virtual.next_enrollment 1,0:500:true,5:250:true,10:150:true,15:500:true
+$ adb shell am start -n com.android.settings/.biometrics.face.FaceEnrollIntroduction
+# If you would like to get rid of the enrollment, run the follwoing command
+$ adb shell setprop persist.vendor.face.virtual.enrollments \"\"
+```
+
+## Authenticating
+
+```shell
+# If enrollment hasn't been setup
+$ adb shell setprop persist.vendor.face.virtual.enrollments 1
+$ adb shell cmd face sync
+# After enrollment has been setup
+$ adb shell setprop vendor.face.virtual.operation_authenticate_duration 800
+$ adb shell setprop vendor.face.virtual.enrollment_hit 1
+# Power button press to simulate auth
+$ adb shell input keyevent 26
+```
diff --git a/biometrics/face/aidl/default/Session.cpp b/biometrics/face/aidl/default/Session.cpp
index 984a1a9..1188459 100644
--- a/biometrics/face/aidl/default/Session.cpp
+++ b/biometrics/face/aidl/default/Session.cpp
@@ -14,139 +14,135 @@
* limitations under the License.
*/
-#include <aidl/android/hardware/biometrics/common/BnCancellationSignal.h>
#include <android-base/logging.h>
#include "Session.h"
namespace aidl::android::hardware::biometrics::face {
-class CancellationSignal : public common::BnCancellationSignal {
- private:
- std::shared_ptr<ISessionCallback> cb_;
+constexpr size_t MAX_WORKER_QUEUE_SIZE = 5;
- public:
- explicit CancellationSignal(std::shared_ptr<ISessionCallback> cb) : cb_(std::move(cb)) {}
-
- ndk::ScopedAStatus cancel() override {
- cb_->onError(Error::CANCELED, 0 /* vendorCode */);
- return ndk::ScopedAStatus::ok();
- }
-};
-
-Session::Session(std::shared_ptr<ISessionCallback> cb)
- : cb_(std::move(cb)), mRandom(std::mt19937::default_seed) {}
+Session::Session(std::unique_ptr<FakeFaceEngine> engine, std::shared_ptr<ISessionCallback> cb)
+ : mEngine(std::move(engine)), mCb(std::move(cb)), mRandom(std::mt19937::default_seed) {
+ mThread = std::make_unique<WorkerThread>(MAX_WORKER_QUEUE_SIZE);
+}
ndk::ScopedAStatus Session::generateChallenge() {
LOG(INFO) << "generateChallenge";
- if (cb_) {
- std::uniform_int_distribution<int64_t> dist;
- auto challenge = dist(mRandom);
- cb_->onChallengeGenerated(challenge);
- }
+ mThread->schedule(Callable::from([this] { mEngine->generateChallengeImpl(mCb.get()); }));
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::revokeChallenge(int64_t challenge) {
LOG(INFO) << "revokeChallenge";
- if (cb_) {
- cb_->onChallengeRevoked(challenge);
- }
+ mThread->schedule(Callable::from(
+ [this, challenge] { mEngine->revokeChallengeImpl(mCb.get(), challenge); }));
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus Session::getEnrollmentConfig(EnrollmentType /*enrollmentType*/,
- std::vector<EnrollmentStageConfig>* return_val) {
- *return_val = {};
+ndk::ScopedAStatus Session::getEnrollmentConfig(
+ EnrollmentType /*enrollmentType*/, std::vector<EnrollmentStageConfig>* cancellationSignal) {
+ *cancellationSignal = {};
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::enroll(
- const keymaster::HardwareAuthToken& /*hat*/, EnrollmentType /*enrollmentType*/,
- const std::vector<Feature>& /*features*/,
- const std::optional<NativeHandle>& /*previewSurface*/,
- std::shared_ptr<biometrics::common::ICancellationSignal>* /*return_val*/) {
+ const keymaster::HardwareAuthToken& hat, EnrollmentType enrollmentType,
+ const std::vector<Feature>& features, const std::optional<NativeHandle>& /*previewSurface*/,
+ std::shared_ptr<biometrics::common::ICancellationSignal>* cancellationSignal) {
LOG(INFO) << "enroll";
- if (cb_) {
- cb_->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
- }
+ std::promise<void> cancellationPromise;
+ auto cancFuture = cancellationPromise.get_future();
+
+ mThread->schedule(Callable::from(
+ [this, hat, enrollmentType, features, cancFuture = std::move(cancFuture)] {
+ mEngine->enrollImpl(mCb.get(), hat, enrollmentType, features, cancFuture);
+ }));
+
+ *cancellationSignal = SharedRefBase::make<CancellationSignal>(std::move(cancellationPromise));
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus Session::authenticate(int64_t /*keystoreOperationId*/,
- std::shared_ptr<common::ICancellationSignal>* return_val) {
+ndk::ScopedAStatus Session::authenticate(
+ int64_t keystoreOperationId,
+ std::shared_ptr<common::ICancellationSignal>* cancellationSignal) {
LOG(INFO) << "authenticate";
- if (cb_) {
- cb_->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
- }
- *return_val = SharedRefBase::make<CancellationSignal>(cb_);
+ std::promise<void> cancellationPromise;
+ auto cancFuture = cancellationPromise.get_future();
+
+ mThread->schedule(
+ Callable::from([this, keystoreOperationId, cancFuture = std::move(cancFuture)] {
+ mEngine->authenticateImpl(mCb.get(), keystoreOperationId, cancFuture);
+ }));
+
+ *cancellationSignal = SharedRefBase::make<CancellationSignal>(std::move(cancellationPromise));
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::detectInteraction(
- std::shared_ptr<common::ICancellationSignal>* /*return_val*/) {
+ std::shared_ptr<common::ICancellationSignal>* cancellationSignal) {
LOG(INFO) << "detectInteraction";
+ std::promise<void> cancellationPromise;
+ auto cancFuture = cancellationPromise.get_future();
+
+ mThread->schedule(Callable::from([this, cancFuture = std::move(cancFuture)] {
+ mEngine->detectInteractionImpl(mCb.get(), cancFuture);
+ }));
+
+ *cancellationSignal = SharedRefBase::make<CancellationSignal>(std::move(cancellationPromise));
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::enumerateEnrollments() {
LOG(INFO) << "enumerateEnrollments";
- if (cb_) {
- cb_->onEnrollmentsEnumerated(std::vector<int32_t>());
- }
+ mThread->schedule(Callable::from([this] { mEngine->enumerateEnrollmentsImpl(mCb.get()); }));
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& /*enrollmentIds*/) {
+ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& enrollmentIds) {
LOG(INFO) << "removeEnrollments";
- if (cb_) {
- cb_->onEnrollmentsRemoved(std::vector<int32_t>());
- }
+ mThread->schedule(Callable::from(
+ [this, enrollmentIds] { mEngine->removeEnrollmentsImpl(mCb.get(), enrollmentIds); }));
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::getFeatures() {
LOG(INFO) << "getFeatures";
- if (cb_) {
- // Must error out with UNABLE_TO_PROCESS when no faces are enrolled.
- cb_->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
- }
+ mThread->schedule(Callable::from([this] { mEngine->getFeaturesImpl(mCb.get()); }));
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus Session::setFeature(const keymaster::HardwareAuthToken& /*hat*/,
- Feature /*feature*/, bool /*enabled*/) {
+ndk::ScopedAStatus Session::setFeature(const keymaster::HardwareAuthToken& hat, Feature feature,
+ bool enabled) {
LOG(INFO) << "setFeature";
+ mThread->schedule(Callable::from([this, hat, feature, enabled] {
+ mEngine->setFeatureImpl(mCb.get(), hat, feature, enabled);
+ }));
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::getAuthenticatorId() {
LOG(INFO) << "getAuthenticatorId";
- if (cb_) {
- cb_->onAuthenticatorIdRetrieved(0 /* authenticatorId */);
- }
+ mThread->schedule(Callable::from([this] { mEngine->getAuthenticatorIdImpl(mCb.get()); }));
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::invalidateAuthenticatorId() {
LOG(INFO) << "invalidateAuthenticatorId";
- if (cb_) {
- cb_->onAuthenticatorIdInvalidated(0);
- }
+ mThread->schedule(
+ Callable::from([this] { mEngine->invalidateAuthenticatorIdImpl(mCb.get()); }));
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus Session::resetLockout(const keymaster::HardwareAuthToken& /*hat*/) {
+ndk::ScopedAStatus Session::resetLockout(const keymaster::HardwareAuthToken& hat) {
LOG(INFO) << "resetLockout";
- if (cb_) {
- cb_->onLockoutCleared();
- }
+ mThread->schedule(Callable::from([this, hat] { mEngine->resetLockoutImpl(mCb.get(), hat); }));
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::close() {
- if (cb_) {
- cb_->onSessionClosed();
+ if (mCb) {
+ mCb->onSessionClosed();
}
return ndk::ScopedAStatus::ok();
}
diff --git a/biometrics/face/aidl/default/Session.h b/biometrics/face/aidl/default/Session.h
index 9db17d2..7ca6a1f 100644
--- a/biometrics/face/aidl/default/Session.h
+++ b/biometrics/face/aidl/default/Session.h
@@ -21,6 +21,10 @@
#include <aidl/android/hardware/biometrics/face/BnSession.h>
#include <aidl/android/hardware/biometrics/face/ISessionCallback.h>
+#include "FakeFaceEngine.h"
+#include "thread/WorkerThread.h"
+#include "util/CancellationSignal.h"
+
namespace aidl::android::hardware::biometrics::face {
namespace common = aidl::android::hardware::biometrics::common;
@@ -30,7 +34,7 @@
class Session : public BnSession {
public:
- explicit Session(std::shared_ptr<ISessionCallback> cb);
+ explicit Session(std::unique_ptr<FakeFaceEngine> engine, std::shared_ptr<ISessionCallback> cb);
ndk::ScopedAStatus generateChallenge() override;
@@ -85,8 +89,11 @@
ndk::ScopedAStatus onContextChanged(const common::OperationContext& context) override;
private:
- std::shared_ptr<ISessionCallback> cb_;
+ std::unique_ptr<FakeFaceEngine> mEngine;
+ std::shared_ptr<ISessionCallback> mCb;
std::mt19937 mRandom;
+ std::unique_ptr<WorkerThread> mThread;
+ std::shared_ptr<CancellationSignal> mCancellationSignal;
};
} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
new file mode 100644
index 0000000..9548920
--- /dev/null
+++ b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
@@ -0,0 +1,98 @@
+props {
+ owner: Vendor
+ module: "android.face.virt.FaceHalProperties"
+ prop {
+ api_name: "authenticator_id"
+ type: Long
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.authenticator_id"
+ }
+ prop {
+ api_name: "challenge"
+ type: Long
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.challenge"
+ }
+ prop {
+ api_name: "enrollment_hit"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.enrollment_hit"
+ }
+ prop {
+ api_name: "enrollments"
+ type: IntegerList
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.enrollments"
+ }
+ prop {
+ api_name: "features"
+ type: IntegerList
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.features"
+ }
+ prop {
+ api_name: "lockout"
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.lockout"
+ }
+ prop {
+ api_name: "next_enrollment"
+ type: String
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.next_enrollment"
+ }
+ prop {
+ api_name: "operation_authenticate_duration"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_authenticate_duration"
+ }
+ prop {
+ api_name: "operation_authenticate_fails"
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_authenticate_fails"
+ }
+ prop {
+ api_name: "operation_authenticate_latency"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_authenticate_latency"
+ }
+ prop {
+ api_name: "operation_detect_interaction_fails"
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
+ }
+ prop {
+ api_name: "operation_detect_interaction_latency"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
+ }
+ prop {
+ api_name: "operation_enroll_fails"
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_enroll_fails"
+ }
+ prop {
+ api_name: "operation_start_enroll_latency"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_start_enroll_latency"
+ }
+ prop {
+ api_name: "strength"
+ type: String
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.strength"
+ enum_values: "convenience|weak|strong"
+ }
+ prop {
+ api_name: "type"
+ type: String
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.type"
+ enum_values: "IR|RGB"
+ }
+}
diff --git a/biometrics/face/aidl/default/face.sysprop b/biometrics/face/aidl/default/face.sysprop
new file mode 100644
index 0000000..6b0f37f
--- /dev/null
+++ b/biometrics/face/aidl/default/face.sysprop
@@ -0,0 +1,159 @@
+# face.sysprop
+# module becomes static class (Java) / namespace (C++) for serving API
+module: "android.face.virt.FaceHalProperties"
+owner: Vendor
+
+# type of face sensor
+prop {
+ prop_name: "persist.vendor.face.virtual.type"
+ type: String
+ scope: Public
+ access: ReadWrite
+ enum_values: "IR|RGB"
+ api_name: "type"
+}
+
+# the strength of the sensor
+prop {
+ prop_name: "persist.vendor.face.virtual.strength"
+ type: String
+ scope: Public
+ access: ReadWrite
+ enum_values: "convenience|weak|strong"
+ api_name: "strength"
+}
+
+# ids of current enrollments
+prop {
+ prop_name: "persist.vendor.face.virtual.enrollments"
+ type: IntegerList
+ scope: Public
+ access: ReadWrite
+ api_name: "enrollments"
+}
+
+# List of features
+prop {
+ prop_name: "persist.vendor.face.virtual.features"
+ type: IntegerList
+ scope: Public
+ access: ReadWrite
+ api_name: "features"
+}
+
+# authenticate and detectInteraction will succeed with this
+# enrollment id, when present, otherwise they will error
+prop {
+ prop_name: "vendor.face.virtual.enrollment_hit"
+ type: Integer
+ scope: Public
+ access: ReadWrite
+ api_name: "enrollment_hit"
+}
+
+# The initial latency for enrollment
+prop {
+ prop_name: "vendor.face.virtual.operation_start_enroll_latency"
+ type: Integer
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_start_enroll_latency"
+}
+
+# the next enrollment in the format:
+# "<id>,<bucket_id>:<delay>:<succeeds>,<bucket_id>..."
+# for example: "0:1,0:100:1,1:200:1" indicating that bucket 0 took
+# 50 milliseconds, bucket 1 took 100 milliseconds, bucket 2 took 200 milliseconds.
+# Note that it is up to the configuration to determine how many buckets are required
+# to complete an enrollment
+prop {
+ prop_name: "vendor.face.virtual.next_enrollment"
+ type: String
+ scope: Public
+ access: ReadWrite
+ api_name: "next_enrollment"
+}
+
+# value for getAuthenticatorId or 0
+prop {
+ prop_name: "vendor.face.virtual.authenticator_id"
+ type: Long
+ scope: Public
+ access: ReadWrite
+ api_name: "authenticator_id"
+}
+
+# value for generateChallenge
+prop {
+ prop_name: "vendor.face.virtual.challenge"
+ type: Long
+ scope: Public
+ access: ReadWrite
+ api_name: "challenge"
+}
+
+# if locked out
+prop {
+ prop_name: "vendor.face.virtual.lockout"
+ type: Boolean
+ scope: Public
+ access: ReadWrite
+ api_name: "lockout"
+}
+
+# force all authenticate operations to fail
+prop {
+ prop_name: "vendor.face.virtual.operation_authenticate_fails"
+ type: Boolean
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_authenticate_fails"
+}
+
+# force all detectInteraction operations to fail
+prop {
+ prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
+ type: Boolean
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_detect_interaction_fails"
+}
+
+# force all enroll operations to fail
+prop {
+ prop_name: "vendor.face.virtual.operation_enroll_fails"
+ type: Boolean
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_enroll_fails"
+}
+
+# add a latency to authentication operations
+# Note that this latency is the initial authentication latency that occurs before
+# the HAL will send AcquiredInfo::START and AcquiredInfo::FIRST_FRAME_RECEIVED
+prop {
+ prop_name: "vendor.face.virtual.operation_authenticate_latency"
+ type: Integer
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_authenticate_latency"
+}
+
+# add a latency to detectInteraction operations
+prop {
+ prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
+ type: Integer
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_detect_interaction_latency"
+}
+
+# millisecond duration for authenticate operations
+# (waits for changes to enrollment_hit)
+prop {
+ prop_name: "vendor.face.virtual.operation_authenticate_duration"
+ type: Integer
+ scope: Public
+ access: ReadWrite
+ api_name: "operation_authenticate_duration"
+}
diff --git a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
new file mode 100644
index 0000000..c8ad6b7
--- /dev/null
+++ b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
@@ -0,0 +1,383 @@
+/*
+ * 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 <face.sysprop.h>
+#include <gtest/gtest.h>
+
+#include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
+#include <android-base/logging.h>
+
+#include "FakeFaceEngine.h"
+
+using namespace ::android::face::virt;
+using namespace ::aidl::android::hardware::biometrics::face;
+using namespace ::aidl::android::hardware::keymaster;
+
+namespace aidl::android::hardware::biometrics::face {
+
+class TestSessionCallback : public BnSessionCallback {
+ public:
+ ndk::ScopedAStatus onChallengeGenerated(int64_t challenge) override {
+ mLastChallenge = challenge;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onChallengeRevoked(int64_t challenge) override {
+ mLastChallengeRevoked = challenge;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onError(Error error, int32_t) override {
+ mError = error;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onEnrollmentProgress(int32_t enrollmentId, int32_t remaining) override {
+ if (remaining == 0) mLastEnrolled = enrollmentId;
+ return ndk::ScopedAStatus::ok();
+ };
+
+ ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t enrollmentId,
+ const HardwareAuthToken&) override {
+ mLastAuthenticated = enrollmentId;
+ mAuthenticateFailed = false;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onAuthenticationFailed() override {
+ mLastAuthenticated = 0;
+ mAuthenticateFailed = true;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onInteractionDetected() override {
+ mInteractionDetectedCount++;
+ return ndk::ScopedAStatus::ok();
+ };
+
+ ::ndk::ScopedAStatus onEnrollmentFrame(const EnrollmentFrame& frame) override {
+ mEnrollmentFrames.push_back(frame.data.vendorCode);
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ::ndk::ScopedAStatus onEnrollmentsEnumerated(
+ const std::vector<int32_t>& enrollmentIds) override {
+ mLastEnrollmentsEnumerated = enrollmentIds;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onEnrollmentsRemoved(const std::vector<int32_t>& enrollmentIds) override {
+ mLastEnrollmentRemoved = enrollmentIds;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t authenticatorId) override {
+ mLastAuthenticatorId = authenticatorId;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t authenticatorId) override {
+ mLastAuthenticatorId = authenticatorId;
+ mAuthenticatorIdInvalidated = true;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onAuthenticationFrame(const AuthenticationFrame& /*authFrame*/) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onLockoutPermanent() override {
+ mLockoutPermanent = true;
+ return ndk::ScopedAStatus::ok();
+ };
+ ::ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onLockoutCleared() override {
+ mLockoutPermanent = false;
+ return ndk::ScopedAStatus::ok();
+ }
+ ::ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
+
+ ::ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>& features) override {
+ mFeatures = features;
+ return ndk::ScopedAStatus::ok();
+ }
+
+ ::ndk::ScopedAStatus onFeatureSet(Feature feature) override {
+ mLastFeatureSet = feature;
+ return ndk::ScopedAStatus::ok();
+ }
+
+ Error mError = Error::UNKNOWN;
+ int64_t mLastChallenge = -1;
+ int64_t mLastChallengeRevoked = -1;
+ int32_t mLastEnrolled = -1;
+ int32_t mLastAuthenticated = -1;
+ int64_t mLastAuthenticatorId = -1;
+ std::vector<int32_t> mLastEnrollmentsEnumerated;
+ std::vector<int32_t> mLastEnrollmentRemoved;
+ std::vector<Feature> mFeatures;
+ Feature mLastFeatureSet;
+ std::vector<int32_t> mEnrollmentFrames;
+ bool mAuthenticateFailed = false;
+ bool mAuthenticatorIdInvalidated = false;
+ bool mLockoutPermanent = false;
+ int mInteractionDetectedCount = 0;
+};
+
+class FakeFaceEngineTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ LOG(ERROR) << "JRM SETUP";
+ mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
+ FaceHalProperties::enrollments({});
+ FaceHalProperties::challenge({});
+ FaceHalProperties::features({});
+ FaceHalProperties::authenticator_id({});
+ FaceHalProperties::strength("");
+ }
+
+ FakeFaceEngine mEngine;
+ std::shared_ptr<TestSessionCallback> mCallback;
+ std::promise<void> mCancel;
+};
+
+TEST_F(FakeFaceEngineTest, one_eq_one) {
+ ASSERT_EQ(1, 1);
+}
+
+TEST_F(FakeFaceEngineTest, GenerateChallenge) {
+ mEngine.generateChallengeImpl(mCallback.get());
+ ASSERT_EQ(FaceHalProperties::challenge().value(), mCallback->mLastChallenge);
+}
+
+TEST_F(FakeFaceEngineTest, RevokeChallenge) {
+ auto challenge = FaceHalProperties::challenge().value_or(10);
+ mEngine.revokeChallengeImpl(mCallback.get(), challenge);
+ ASSERT_FALSE(FaceHalProperties::challenge().has_value());
+ ASSERT_EQ(challenge, mCallback->mLastChallengeRevoked);
+}
+
+TEST_F(FakeFaceEngineTest, ResetLockout) {
+ FaceHalProperties::lockout(true);
+ mEngine.resetLockoutImpl(mCallback.get(), {});
+ ASSERT_FALSE(mCallback->mLockoutPermanent);
+ ASSERT_FALSE(FaceHalProperties::lockout().value_or(true));
+}
+
+TEST_F(FakeFaceEngineTest, AuthenticatorId) {
+ FaceHalProperties::authenticator_id(50);
+ mEngine.getAuthenticatorIdImpl(mCallback.get());
+ ASSERT_EQ(50, mCallback->mLastAuthenticatorId);
+ ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
+}
+
+TEST_F(FakeFaceEngineTest, GetAuthenticatorIdWeakReturnsZero) {
+ FaceHalProperties::strength("weak");
+ FaceHalProperties::authenticator_id(500);
+ mEngine.getAuthenticatorIdImpl(mCallback.get());
+ ASSERT_EQ(0, mCallback->mLastAuthenticatorId);
+ ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
+}
+
+TEST_F(FakeFaceEngineTest, AuthenticatorIdInvalidate) {
+ FaceHalProperties::authenticator_id(500);
+ mEngine.invalidateAuthenticatorIdImpl(mCallback.get());
+ ASSERT_NE(500, FaceHalProperties::authenticator_id().value());
+ ASSERT_TRUE(mCallback->mAuthenticatorIdInvalidated);
+}
+
+TEST_F(FakeFaceEngineTest, Enroll) {
+ FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:true");
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
+ mCancel.get_future());
+ ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
+ ASSERT_EQ(1, FaceHalProperties::enrollments().size());
+ ASSERT_EQ(1, FaceHalProperties::enrollments()[0].value());
+ ASSERT_EQ(1, mCallback->mLastEnrolled);
+}
+
+TEST_F(FakeFaceEngineTest, EnrollFails) {
+ FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:false");
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
+ mCancel.get_future());
+ ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
+ ASSERT_EQ(0, FaceHalProperties::enrollments().size());
+}
+
+TEST_F(FakeFaceEngineTest, EnrollCancel) {
+ FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:false");
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mCancel.set_value();
+ mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
+ mCancel.get_future());
+ ASSERT_EQ(Error::CANCELED, mCallback->mError);
+ ASSERT_EQ(-1, mCallback->mLastEnrolled);
+ ASSERT_EQ(0, FaceHalProperties::enrollments().size());
+ ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
+}
+
+TEST_F(FakeFaceEngineTest, Authenticate) {
+ FaceHalProperties::enrollments({100});
+ FaceHalProperties::enrollment_hit(100);
+ mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
+
+ ASSERT_EQ(100, mCallback->mLastAuthenticated);
+ ASSERT_FALSE(mCallback->mAuthenticateFailed);
+}
+
+TEST_F(FakeFaceEngineTest, AuthenticateCancel) {
+ FaceHalProperties::enrollments({100});
+ FaceHalProperties::enrollment_hit(100);
+ mCancel.set_value();
+ mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
+ ASSERT_EQ(Error::CANCELED, mCallback->mError);
+}
+
+TEST_F(FakeFaceEngineTest, AuthenticateFailedForUnEnrolled) {
+ FaceHalProperties::enrollments({3});
+ FaceHalProperties::enrollment_hit(100);
+ mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
+ ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
+ ASSERT_TRUE(mCallback->mAuthenticateFailed);
+}
+
+TEST_F(FakeFaceEngineTest, DetectInteraction) {
+ FaceHalProperties::enrollments({100});
+ FaceHalProperties::enrollment_hit(100);
+ ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
+ mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+ ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
+}
+
+TEST_F(FakeFaceEngineTest, DetectInteractionCancel) {
+ FaceHalProperties::enrollments({100});
+ FaceHalProperties::enrollment_hit(100);
+ mCancel.set_value();
+ mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
+ ASSERT_EQ(Error::CANCELED, mCallback->mError);
+}
+
+TEST_F(FakeFaceEngineTest, GetFeatureEmpty) {
+ mEngine.getFeaturesImpl(mCallback.get());
+ ASSERT_TRUE(mCallback->mFeatures.empty());
+}
+
+TEST_F(FakeFaceEngineTest, SetFeature) {
+ FaceHalProperties::enrollments({1});
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
+ auto features = mCallback->mFeatures;
+ ASSERT_TRUE(features.empty());
+ ASSERT_EQ(Feature::REQUIRE_ATTENTION, mCallback->mLastFeatureSet);
+
+ mEngine.getFeaturesImpl(mCallback.get());
+ features = mCallback->mFeatures;
+ ASSERT_FALSE(features.empty());
+ ASSERT_NE(features.end(),
+ std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
+}
+
+TEST_F(FakeFaceEngineTest, ToggleFeature) {
+ FaceHalProperties::enrollments({1});
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
+ mEngine.getFeaturesImpl(mCallback.get());
+ auto features = mCallback->mFeatures;
+ ASSERT_FALSE(features.empty());
+ ASSERT_NE(features.end(),
+ std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
+
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
+ mEngine.getFeaturesImpl(mCallback.get());
+ features = mCallback->mFeatures;
+ ASSERT_TRUE(features.empty());
+}
+
+TEST_F(FakeFaceEngineTest, TurningOffNonExistentFeatureDoesNothing) {
+ FaceHalProperties::enrollments({1});
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
+ mEngine.getFeaturesImpl(mCallback.get());
+ auto features = mCallback->mFeatures;
+ ASSERT_TRUE(features.empty());
+}
+
+TEST_F(FakeFaceEngineTest, SetMultipleFeatures) {
+ FaceHalProperties::enrollments({1});
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, true);
+ mEngine.getFeaturesImpl(mCallback.get());
+ auto features = mCallback->mFeatures;
+ ASSERT_EQ(3, features.size());
+ ASSERT_NE(features.end(),
+ std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
+ ASSERT_NE(features.end(),
+ std::find(features.begin(), features.end(), Feature::REQUIRE_DIVERSE_POSES));
+ ASSERT_NE(features.end(), std::find(features.begin(), features.end(), Feature::DEBUG));
+}
+
+TEST_F(FakeFaceEngineTest, SetMultipleFeaturesAndTurnOffSome) {
+ FaceHalProperties::enrollments({1});
+ keymaster::HardwareAuthToken hat{.mac = {2, 4}};
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, true);
+ mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, false);
+ mEngine.getFeaturesImpl(mCallback.get());
+ auto features = mCallback->mFeatures;
+ ASSERT_EQ(2, features.size());
+ ASSERT_NE(features.end(),
+ std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
+ ASSERT_NE(features.end(),
+ std::find(features.begin(), features.end(), Feature::REQUIRE_DIVERSE_POSES));
+ ASSERT_EQ(features.end(), std::find(features.begin(), features.end(), Feature::DEBUG));
+}
+
+TEST_F(FakeFaceEngineTest, Enumerate) {
+ FaceHalProperties::enrollments({120, 3});
+ mEngine.enumerateEnrollmentsImpl(mCallback.get());
+ auto enrolls = mCallback->mLastEnrollmentsEnumerated;
+ ASSERT_FALSE(enrolls.empty());
+ ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 120));
+ ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 3));
+}
+
+TEST_F(FakeFaceEngineTest, RemoveEnrollments) {
+ FaceHalProperties::enrollments({120, 3, 100});
+ mEngine.removeEnrollmentsImpl(mCallback.get(), {120, 100});
+ mEngine.enumerateEnrollmentsImpl(mCallback.get());
+ auto enrolls = mCallback->mLastEnrollmentsEnumerated;
+ ASSERT_FALSE(enrolls.empty());
+ ASSERT_EQ(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 120));
+ ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 3));
+ ASSERT_EQ(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 100));
+}
+
+TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) {
+ FaceHalProperties::lockout(true);
+ FaceHalProperties::enrollments({33});
+ FaceHalProperties::enrollment_hit(33);
+ auto cancelFuture = mCancel.get_future();
+ mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
+
+ ASSERT_TRUE(mCallback->mLockoutPermanent);
+
+ mEngine.resetLockoutImpl(mCallback.get(), {} /* hat */);
+ ASSERT_FALSE(mCallback->mLockoutPermanent);
+ FaceHalProperties::enrollment_hit(33);
+ mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
+ ASSERT_EQ(33, mCallback->mLastAuthenticated);
+ ASSERT_FALSE(mCallback->mAuthenticateFailed);
+}
+
+} // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
diff --git a/biometrics/fingerprint/aidl/OWNERS b/biometrics/fingerprint/aidl/OWNERS
index 36d7261..e162d2d 100644
--- a/biometrics/fingerprint/aidl/OWNERS
+++ b/biometrics/fingerprint/aidl/OWNERS
@@ -1,2 +1,4 @@
ilyamaty@google.com
-kchyn@google.com
+jeffpu@google.com
+jbolinger@google.com
+joshmccloskey@google.com
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index 70fadfe..31fd96b 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -15,11 +15,9 @@
vintf_fragments: ["fingerprint-example.xml"],
local_include_dirs: ["include"],
srcs: [
- "CancellationSignal.cpp",
"FakeFingerprintEngine.cpp",
"Fingerprint.cpp",
"Session.cpp",
- "WorkerThread.cpp",
"main.cpp",
],
shared_libs: [
@@ -27,28 +25,16 @@
"libbinder_ndk",
"android.hardware.biometrics.fingerprint-V2-ndk",
"android.hardware.biometrics.common-V2-ndk",
+ "android.hardware.biometrics.common.thread",
+ "android.hardware.biometrics.common.util",
],
static_libs: ["android.hardware.biometrics.fingerprint.VirtualProps"],
}
-cc_test_host {
- name: "android.hardware.biometrics.fingerprint.WorkerThreadTest",
- local_include_dirs: ["include"],
- srcs: [
- "tests/WorkerThreadTest.cpp",
- "WorkerThread.cpp",
- ],
- shared_libs: [
- "libcutils",
- ],
- test_suites: ["general-tests"],
-}
-
cc_test {
name: "android.hardware.biometrics.fingerprint.FakeFingerprintEngineTest",
local_include_dirs: ["include"],
srcs: [
- "CancellationSignal.cpp",
"tests/FakeFingerprintEngineTest.cpp",
"FakeFingerprintEngine.cpp",
],
@@ -61,6 +47,7 @@
"android.hardware.biometrics.fingerprint-V2-ndk",
"android.hardware.biometrics.common-V2-ndk",
"android.hardware.keymaster-V3-ndk",
+ "android.hardware.biometrics.common.util",
],
vendor: true,
test_suites: ["general-tests"],
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index d1fe183..138caa0 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -16,53 +16,14 @@
#include "FakeFingerprintEngine.h"
-#include <fingerprint.sysprop.h>
-#include "CancellationSignal.h"
-
#include <android-base/logging.h>
-#include <chrono>
-#include <regex>
-#include <thread>
-#define SLEEP_MS(x) \
- if (x > 0) std::this_thread::sleep_for(std::chrono::milliseconds(x))
-#define BEGIN_OP(x) \
- do { \
- LOG(INFO) << __func__; \
- SLEEP_MS(x); \
- } while (0)
-#define IS_TRUE(x) ((x == "1") || (x == "true"))
+#include <fingerprint.sysprop.h>
-// This is for non-test situations, such as casual cuttlefish users, that don't
-// set an explicit value.
-// Some operations (i.e. enroll, authenticate) will be executed in tight loops
-// by parts of the UI or fail if there is no latency. For example, the
-// fingerprint 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 2000
+#include "util/CancellationSignal.h"
+#include "util/Util.h"
using namespace ::android::fingerprint::virt;
-using namespace ::aidl::android::hardware::biometrics::fingerprint;
-
-int64_t getSystemNanoTime() {
- timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
- return now.tv_sec * 1000000000LL + now.tv_nsec;
-}
-
-bool hasElapsed(int64_t start, int64_t durationMillis) {
- auto now = getSystemNanoTime();
- if (now < start) return true;
- if (durationMillis <= 0) return true;
- return ((now - start) / 1000000LL) > durationMillis;
-}
-
-std::vector<std::string> split(const std::string& str, const std::string& sep) {
- std::regex regex(sep);
- std::vector<std::string> parts(std::sregex_token_iterator(str.begin(), str.end(), regex, -1),
- std::sregex_token_iterator());
- return parts;
-}
namespace aidl::android::hardware::biometrics::fingerprint {
@@ -100,14 +61,14 @@
// format is "<id>:<progress_ms>,<progress_ms>,...:<result>
auto nextEnroll = FingerprintHalProperties::next_enrollment().value_or("");
- auto parts = split(nextEnroll, ":");
+ auto parts = Util::split(nextEnroll, ":");
if (parts.size() != 3) {
LOG(ERROR) << "Fail: invalid next_enrollment";
cb->onError(Error::VENDOR, 0 /* vendorError */);
return;
}
auto enrollmentId = std::stoi(parts[0]);
- auto progress = split(parts[1], ",");
+ auto progress = Util::split(parts[1], ",");
for (size_t i = 0; i < progress.size(); i++) {
auto left = progress.size() - i - 1;
SLEEP_MS(std::stoi(progress[i]));
@@ -140,7 +101,7 @@
const std::future<void>& cancel) {
BEGIN_OP(FingerprintHalProperties::operation_authenticate_latency().value_or(DEFAULT_LATENCY));
- auto now = getSystemNanoTime();
+ auto now = Util::getSystemNanoTime();
int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(0);
do {
if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
@@ -171,7 +132,7 @@
}
SLEEP_MS(100);
- } while (!hasElapsed(now, duration));
+ } while (!Util::hasElapsed(now, duration));
LOG(ERROR) << "Fail: not enrolled";
cb->onAuthenticationFailed();
diff --git a/biometrics/fingerprint/aidl/default/Session.cpp b/biometrics/fingerprint/aidl/default/Session.cpp
index 078d3d9..ab91e98 100644
--- a/biometrics/fingerprint/aidl/default/Session.cpp
+++ b/biometrics/fingerprint/aidl/default/Session.cpp
@@ -18,7 +18,7 @@
#include <android-base/logging.h>
-#include "CancellationSignal.h"
+#include "util/CancellationSignal.h"
namespace aidl::android::hardware::biometrics::fingerprint {
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 8659b79..eb810da 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -15,12 +15,13 @@
*/
#pragma once
-
+#include <aidl/android/hardware/biometrics/common/SensorStrength.h>
#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
#include <random>
-#include "CancellationSignal.h"
+#include <future>
+#include <vector>
using namespace ::aidl::android::hardware::biometrics::common;
diff --git a/biometrics/fingerprint/aidl/default/include/Fingerprint.h b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
index 7bd3d6d..20def0c 100644
--- a/biometrics/fingerprint/aidl/default/include/Fingerprint.h
+++ b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
@@ -20,7 +20,7 @@
#include "FakeFingerprintEngine.h"
#include "Session.h"
-#include "WorkerThread.h"
+#include "thread/WorkerThread.h"
namespace aidl::android::hardware::biometrics::fingerprint {
diff --git a/biometrics/fingerprint/aidl/default/include/Session.h b/biometrics/fingerprint/aidl/default/include/Session.h
index acd5def..104d819 100644
--- a/biometrics/fingerprint/aidl/default/include/Session.h
+++ b/biometrics/fingerprint/aidl/default/include/Session.h
@@ -20,7 +20,7 @@
#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
#include "FakeFingerprintEngine.h"
-#include "WorkerThread.h"
+#include "thread/WorkerThread.h"
namespace aidl::android::hardware::biometrics::fingerprint {
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
index d64751a..98b62ef 100644
--- a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
@@ -20,8 +20,11 @@
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
</target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
- <option name="bluetooth" value="off" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
+ <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
+ <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+ <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
diff --git a/camera/device/3.8/Android.bp b/camera/device/3.8/Android.bp
deleted file mode 100644
index c3c2941..0000000
--- a/camera/device/3.8/Android.bp
+++ /dev/null
@@ -1,39 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-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"],
-}
-
-hidl_interface {
- name: "android.hardware.camera.device@3.8",
- root: "android.hardware",
- srcs: [
- "types.hal",
- "ICameraDevice.hal",
- "ICameraDeviceCallback.hal",
- "ICameraDeviceSession.hal",
- ],
- interfaces: [
- "android.hardware.camera.common@1.0",
- "android.hardware.camera.device@3.2",
- "android.hardware.camera.device@3.3",
- "android.hardware.camera.device@3.4",
- "android.hardware.camera.device@3.5",
- "android.hardware.camera.device@3.6",
- "android.hardware.camera.device@3.7",
- "android.hardware.camera.metadata@3.2",
- "android.hardware.camera.metadata@3.3",
- "android.hardware.camera.metadata@3.4",
- "android.hardware.camera.metadata@3.5",
- "android.hardware.camera.metadata@3.6",
- "android.hardware.camera.metadata@3.8",
- "android.hardware.graphics.common@1.0",
- "android.hidl.base@1.0",
- ],
- gen_java: false,
-}
diff --git a/camera/device/3.8/ICameraDevice.hal b/camera/device/3.8/ICameraDevice.hal
deleted file mode 100644
index 09edb8b..0000000
--- a/camera/device/3.8/ICameraDevice.hal
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera.device@3.8;
-
-import android.hardware.camera.common@1.0::Status;
-import @3.7::ICameraDevice;
-
-/**
- * Camera device interface
- *
- * Supports the android.hardware.Camera API, and the android.hardware.camera2
- * API at LIMITED or better hardware level.
- *
- * ICameraDevice.open() must return @3.2::ICameraDeviceSession,
- * @3.5::ICameraDeviceSession, @3.6::ICameraDeviceSession,
- * @3.7::ICameraDeviceSession, or @3.8::ICameraDeviceSession.
- */
-interface ICameraDevice extends @3.7::ICameraDevice {
- /**
- * turnOnTorchWithStrengthLevel:
- *
- * Change the brightness level of the flash unit associated with this camera device
- * and set it to value in torchStrength. This function also turns ON the torch
- * with specified torchStrength if the torch is OFF.
- *
- * The torchStrength value must be within the valid range i.e. >=1 and
- * <= FLASH_INFO_STRENGTH_MAXIMUM_LEVEL. Whenever the torch is turned OFF,
- * the brightness level will reset to FLASH_INFO_STRENGTH_DEFAULT_LEVEL.
- * When the client calls setTorchMode(ON) after turnOnTorchWithStrengthLevel(N),
- * the flash unit will have brightness level equal to N. This level does not
- * represent the real brightness units. It is linear in nature i.e. flashlight
- * at level 10 is twice as bright as at level 5.
- *
- * @param torchStrength Brightness level to be set for the flashlight.
- *
- * @return status Status code for the operation, one of:
- * OK:
- * On a successful change to the torch strength level.
- * INTERNAL_ERROR:
- * The flash unit cannot be operated due to an unexpected internal
- * error.
- * CAMERA_IN_USE:
- * This status code is returned when:
- * - This camera device has been opened, so the torch cannot be
- * controlled until it is closed.
- * - Due to other camera devices being open, or due to other
- * resource constraints, the torch cannot be controlled currently.
- * ILLEGAL_ARGUMENT:
- * If the torchStrength value is not within the range i.e. < 1 or
- * > FLASH_INFO_STRENGTH_MAXIMUM_LEVEL.
- * METHOD_NOT_SUPPORTED:
- * This status code is returned when:
- * - This camera device does not support direct operation of flashlight
- * torch mode. The framework must open the camera device and turn
- * the torch on through the device interface.
- * - This camera device does not have a flash unit.
- * - This camera device has flash unit but does not support torch
- * strength control.
- * CAMERA_DISCONNECTED:
- * An external camera device has been disconnected, and is no longer
- * available. This camera device interface is now stale, and a new
- * instance must be acquired if the device is reconnected. All
- * subsequent calls on this interface must return
- * CAMERA_DISCONNECTED.
- *
- */
- turnOnTorchWithStrengthLevel(int32_t torchStrength) generates (Status status);
-
- /**
- * getTorchStrengthLevel:
- *
- * Get current torch strength level.
- * If the device supports torch strength control, when the torch is OFF the
- * strength level will reset to default level, so the return
- * value in this case will be equal to FLASH_INFO_STRENGTH_DEFAULT_LEVEL.
- *
- * @return status Status code for the operation, one of:
- * OK:
- * On success.
- * INTERNAL_ERROR:
- * An unexpected error occurred and the information is not
- * available.
- * METHOD_NOT_SUPPORTED:
- * This status code is returned when:
- * - This camera device does not support direct operation of flashlight
- * torch mode. The framework must open the camera device and turn
- * the torch on through the device interface.
- * - This camera device does not have a flash unit.
- * - This camera device has flash unit but does not support torch
- * strength control.
- *
- * @return torchStrength Current torch strength level.
- *
- */
- getTorchStrengthLevel() generates (Status status, int32_t torchStrength);
-
- /**
- * isStreamCombinationSupported_3_8:
- *
- * Identical to @3.7::ICameraDevice.isStreamCombinationSupported, except
- * that it takes a @3.8::StreamConfiguration parameter, which could contain
- * additional information about a specific 10-bit dynamic range profile or
- * stream use case.
- *
- */
- isStreamCombinationSupported_3_8(StreamConfiguration streams)
- generates (Status status, bool queryStatus);
-};
diff --git a/camera/device/3.8/ICameraDeviceCallback.hal b/camera/device/3.8/ICameraDeviceCallback.hal
deleted file mode 100644
index de0775d..0000000
--- a/camera/device/3.8/ICameraDeviceCallback.hal
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera.device@3.8;
-
-import @3.5::ICameraDeviceCallback;
-
-/**
- * Callback methods for the HAL to call into the framework.
- */
-interface ICameraDeviceCallback extends @3.5::ICameraDeviceCallback {
- /**
- * Identical to @3.5::ICameraDeviceCallback.notify, except that it takes a
- * list of @3.8::NotifyMsg which contain readout timestamp in addition
- * to exposure start timestamp for shutter.
- *
- * The readout timestamp is used for the framework to re-time the viewfinder
- * frames targeted for SurfaceView so that preview jitter can be reduced.
- */
- notify_3_8(vec<NotifyMsg> msgs);
-};
diff --git a/camera/device/3.8/ICameraDeviceSession.hal b/camera/device/3.8/ICameraDeviceSession.hal
deleted file mode 100644
index c3aa836..0000000
--- a/camera/device/3.8/ICameraDeviceSession.hal
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera.device@3.8;
-
-import android.hardware.camera.common@1.0::Status;
-import @3.5::StreamConfiguration;
-import @3.7::ICameraDeviceSession;
-import @3.6::HalStreamConfiguration;
-
-/**
- * Camera device active session interface.
- *
- * Obtained via ICameraDevice::open(), this interface contains the methods to
- * configure and request captures from an active camera device.
- */
-interface ICameraDeviceSession extends @3.7::ICameraDeviceSession {
- /**
- * configureStreams_3_8:
- *
- * Identical to @3.7::ICameraDeviceSession.configureStreams_3_7, except that:
- *
- * - The requestedConfiguration allows the camera framework to configure
- * 10-bit dynamic range profile.
- * - The requestedConfiguration allows the camera framework to configure
- * stream use cases.
- *
- * @return status Status code for the operation, one of:
- * OK:
- * On successful stream configuration.
- * INTERNAL_ERROR:
- * If there has been a fatal error and the device is no longer
- * operational. Only close() can be called successfully by the
- * framework after this error is returned.
- * ILLEGAL_ARGUMENT:
- * If the requested stream configuration is invalid. Some examples
- * of invalid stream configurations include:
- * - Including more than 1 INPUT stream
- * - Not including any OUTPUT streams
- * - Including streams with unsupported formats, or an unsupported
- * size for that format.
- * - Including too many output streams of a certain format.
- * - Unsupported rotation configuration
- * - Stream sizes/formats don't satisfy the
- * StreamConfigurationMode requirements
- * for non-NORMAL mode, or the requested operation_mode is not
- * supported by the HAL.
- * - Unsupported usage flag
- * - Unsupported stream groupIds, or unsupported multi-resolution
- * input stream.
- * - Invalid combination between a 10-bit dynamic range profile
- * and none impl. defined 8-bit format for a particular stream.
- * - Unsupported stream use case
- * The camera service cannot filter out all possible illegal stream
- * configurations, since some devices may support more simultaneous
- * streams or larger stream resolutions than the minimum required
- * for a given camera device hardware level. The HAL must return an
- * ILLEGAL_ARGUMENT for any unsupported stream set, and then be
- * ready to accept a future valid stream configuration in a later
- * configureStreams call.
- * @return halConfiguration The stream parameters desired by the HAL for
- * each stream, including maximum buffers, the usage flags, and the
- * override format and dataspace.
- */
- configureStreams_3_8(StreamConfiguration requestedConfiguration)
- generates (Status status, @3.6::HalStreamConfiguration halConfiguration);
-
- /**
- * repeatingRequestEnd:
- *
- * Notification about the last frame number in a repeating request along with the
- * ids of all streams included in the repeating request.
- *
- * This can be called at any point after 'processCaptureRequest' in response
- * to camera clients disabling an active repeating request.
- *
- * Performance requirements:
- * The call must not be blocked for extensive periods and should be extremely lightweight. There
- * must be no frame rate degradation or frame jitter introduced.
- *
- * This method must always succeed, even if the device has encountered a
- * serious error.
- */
- repeatingRequestEnd(uint32_t frameNumber, vec<int32_t> streamIds);
-};
diff --git a/camera/device/3.8/types.hal b/camera/device/3.8/types.hal
deleted file mode 100644
index 04a2450..0000000
--- a/camera/device/3.8/types.hal
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera.device@3.8;
-
-import @3.2::ErrorMsg;
-import @3.2::CameraMetadata;
-import @3.2::MsgType;
-import @3.2::ShutterMsg;
-import @3.2::CameraMetadata;
-import @3.2::StreamConfigurationMode;
-import @3.7::Stream;
-
-import android.hardware.camera.metadata@3.8::CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
-import android.hardware.camera.metadata@3.8::CameraMetadataEnumAndroidScalerAvailableStreamUseCases;
-
-/**
- * ShutterMsg:
- *
- * Message contents for MsgType::SHUTTER
- *
- * This version extends the @3.2 ShutterMsg with the readout timestamp.
- */
-struct ShutterMsg {
- /**
- * The definition of ShutterMsg from prior version.
- */
- @3.2::ShutterMsg v3_2;
-
- /**
- * Timestamp for the capture readout. This must be in the same time domain
- * as v3_2.timestamp, and for a rolling shutter sensor, the value must be
- * v3_2.timestamp + exposureTime + t_crop_top where t_crop_top is the exposure time
- * skew of the cropped lines on the top.
- */
- uint64_t readoutTimestamp;
-};
-
-/**
- * NotifyMsg:
- *
- * The message structure sent to ICameraDevice3Callback::notify()
- *
- * This version extends the @3.2 NotifyMsg with the @3.8 version of ShutterMsg.
- */
-struct NotifyMsg {
- /**
- * The message type.
- */
- @3.2::MsgType type;
-
- union Message {
- /**
- * Error message contents. Valid if type is MsgType::ERROR
- */
- @3.2::ErrorMsg error;
-
- /**
- * Shutter message contents. Valid if type is MsgType::SHUTTER
- */
- ShutterMsg shutter;
- } msg;
-};
-
-/**
- * Stream:
- *
- * A descriptor for a single camera input or output stream. A stream is defined
- * by the framework by its buffer resolution and format, and additionally by the
- * HAL with the gralloc usage flags and the maximum in-flight buffer count.
- *
- * This version extends the @3.7 Stream with the dynamic range profile and the
- * stream use case field.
- */
-struct Stream {
- /**
- * The definition of Stream from the prior version.
- */
- @3.7::Stream v3_7;
-
- /**
- * The dynamic range profile for this stream.
- *
- * This field is valid and must only be considered for streams with format
- * android.hardware.graphics.common.PixelFormat.YCBCR_P010 or
- * android.hardware.graphics.common.PixelFormat.IMPLEMENTATION_DEFINED on devices supporting the
- * ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_10_BIT capability.
- *
- */
- CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap dynamicRangeProfile;
-
- /**
- * The stream use case describing the stream's purpose
- *
- * This flag provides the camera device a hint on what user scenario this
- * stream is intended for. With this flag, the camera device can optimize
- * camera pipeline parameters, such as tuning, sensor mode, and ISP settings,
- * for the intended use case.
- *
- * When this field is set to DEFAULT, the camera device should behave in
- * the same way as in previous HAL versions, and optimize the camera pipeline
- * based on stream format, data space, usage flag, and other stream properties.
- *
- * The HAL reports supported stream use cases in
- * ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES. If the HAL doesn't support
- * setting stream use cases, the camera framework leaves this field as
- * DEFAULT.
- */
- CameraMetadataEnumAndroidScalerAvailableStreamUseCases useCase;
-};
-
-/**
- * StreamConfiguration:
- *
- * Identical to @3.7::StreamConfiguration, except that the streams
- * vector contains @3.8::Stream.
- */
-struct StreamConfiguration {
- /**
- * An array of camera stream pointers, defining the input/output
- * configuration for the camera HAL device.
- */
- vec<Stream> streams;
-
- /**
- * The definition of operation mode from prior version.
- */
- @3.2::StreamConfigurationMode operationMode;
-
- /**
- * The definition of session parameters from prior version.
- */
- @3.2::CameraMetadata sessionParams;
-
- /**
- * The definition of stream configuration counter from prior version.
- */
- uint32_t streamConfigCounter;
-
- /**
- * The definition of multi-resolution input image flag from prior version.
- */
- bool multiResolutionInputImage;
-};
diff --git a/camera/metadata/3.8/Android.bp b/camera/metadata/3.8/Android.bp
deleted file mode 100644
index ead9543..0000000
--- a/camera/metadata/3.8/Android.bp
+++ /dev/null
@@ -1,27 +0,0 @@
-// This file is autogenerated by hidl-gen -Landroidbp.
-
-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"],
-}
-
-hidl_interface {
- name: "android.hardware.camera.metadata@3.8",
- root: "android.hardware",
- srcs: [
- "types.hal",
- ],
- interfaces: [
- "android.hardware.camera.metadata@3.2",
- "android.hardware.camera.metadata@3.3",
- "android.hardware.camera.metadata@3.4",
- "android.hardware.camera.metadata@3.5",
- "android.hardware.camera.metadata@3.6",
- "android.hardware.camera.metadata@3.7",
- ],
- gen_java: true,
-}
diff --git a/camera/metadata/3.8/types.hal b/camera/metadata/3.8/types.hal
deleted file mode 100644
index 8cc6646..0000000
--- a/camera/metadata/3.8/types.hal
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Autogenerated from camera metadata definitions in
- * /system/media/camera/docs/metadata_definitions.xml
- * *** DO NOT EDIT BY HAND ***
- */
-
-package android.hardware.camera.metadata@3.8;
-
-import android.hardware.camera.metadata@3.2;
-import android.hardware.camera.metadata@3.3;
-import android.hardware.camera.metadata@3.4;
-import android.hardware.camera.metadata@3.5;
-import android.hardware.camera.metadata@3.6;
-import android.hardware.camera.metadata@3.7;
-
-/**
- * Top level hierarchy definitions for camera metadata. *_INFO sections are for
- * the static metadata that can be retrieved without opening the camera device.
- */
-enum CameraMetadataSection : @3.4::CameraMetadataSection {
- ANDROID_AUTOMOTIVE =
- android.hardware.camera.metadata@3.4::CameraMetadataSection:ANDROID_SECTION_COUNT,
-
- ANDROID_AUTOMOTIVE_LENS,
-
- ANDROID_SECTION_COUNT_3_8,
-
- VENDOR_SECTION_3_8 = 0x8000,
-
-};
-
-/**
- * Hierarchy positions in enum space. All vendor extension sections must be
- * defined with tag >= VENDOR_SECTION_START
- */
-enum CameraMetadataSectionStart : android.hardware.camera.metadata@3.4::CameraMetadataSectionStart {
- ANDROID_AUTOMOTIVE_START = CameraMetadataSection:ANDROID_AUTOMOTIVE << 16,
-
- ANDROID_AUTOMOTIVE_LENS_START = CameraMetadataSection:ANDROID_AUTOMOTIVE_LENS << 16,
-
- VENDOR_SECTION_START_3_8 = CameraMetadataSection:VENDOR_SECTION_3_8 << 16,
-
-};
-
-/**
- * Main enumeration for defining camera metadata tags added in this revision
- *
- * <p>Partial documentation is included for each tag; for complete documentation, reference
- * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
- */
-enum CameraMetadataTag : @3.7::CameraMetadataTag {
- /** android.flash.info.strengthMaximumLevel [static, int32, public]
- *
- * <p>Maximum flashlight brightness level.</p>
- */
- ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_FLASH_INFO_END,
-
- /** android.flash.info.strengthDefaultLevel [static, int32, public]
- *
- * <p>Default flashlight brightness level to be set via
- * {android.hardware.camera2.CameraManager#turnOnTorchWithStrengthLevel}.</p>
- */
- ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,
-
- ANDROID_FLASH_INFO_END_3_8,
-
- /** android.request.availableDynamicRangeProfilesMap [static, enum[], ndk_public]
- *
- * <p>A map of all available 10-bit dynamic range profiles along with their
- * capture request constraints.</p>
- */
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_REQUEST_END_3_4,
-
- /** android.request.recommendedTenBitDynamicRangeProfile [static, int64, java_public]
- *
- * <p>Recommended 10-bit dynamic range profile.</p>
- */
- ANDROID_REQUEST_RECOMMENDED_TEN_BIT_DYNAMIC_RANGE_PROFILE,
-
- ANDROID_REQUEST_END_3_8,
-
- /** android.scaler.availableStreamUseCases [static, enum[], public]
- *
- * <p>The stream use cases supported by this camera device.</p>
- */
- ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES = android.hardware.camera.metadata@3.6::CameraMetadataTag:ANDROID_SCALER_END_3_6,
-
- ANDROID_SCALER_END_3_8,
-
- /** android.automotive.location [static, enum, public]
- *
- * <p>Location of the cameras on the automotive devices.</p>
- */
- ANDROID_AUTOMOTIVE_LOCATION = CameraMetadataSectionStart:ANDROID_AUTOMOTIVE_START,
-
- ANDROID_AUTOMOTIVE_END_3_8,
-
- /** android.automotive.lens.facing [static, enum[], public]
- *
- * <p>The direction of the camera faces relative to the vehicle body frame and the
- * passenger seats.</p>
- */
- ANDROID_AUTOMOTIVE_LENS_FACING = CameraMetadataSectionStart:ANDROID_AUTOMOTIVE_LENS_START,
-
- ANDROID_AUTOMOTIVE_LENS_END_3_8,
-
-};
-
-/*
- * Enumeration definitions for the various entries that need them
- */
-
-/** android.control.videoStabilizationMode enumeration values added since v3.2
- * @see ANDROID_CONTROL_VIDEO_STABILIZATION_MODE
- */
-enum CameraMetadataEnumAndroidControlVideoStabilizationMode :
- @3.2::CameraMetadataEnumAndroidControlVideoStabilizationMode {
- ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION,
-};
-
-/** android.lens.poseReference enumeration values added since v3.5
- * @see ANDROID_LENS_POSE_REFERENCE
- */
-enum CameraMetadataEnumAndroidLensPoseReference :
- @3.5::CameraMetadataEnumAndroidLensPoseReference {
- ANDROID_LENS_POSE_REFERENCE_AUTOMOTIVE,
-};
-
-/** android.request.availableCapabilities enumeration values added since v3.6
- * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
- */
-enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
- @3.6::CameraMetadataEnumAndroidRequestAvailableCapabilities {
- ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT,
- ANDROID_REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE,
-};
-
-/** android.request.availableDynamicRangeProfilesMap enumeration values
- * @see ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP
- */
-enum CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap : int64_t {
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD
- = 0x1,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10 = 0x2,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10 = 0x4,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS
- = 0x8,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF
- = 0x10,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO
- = 0x20,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM
- = 0x40,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO
- = 0x80,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF
- = 0x100,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO
- = 0x200,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM
- = 0x400,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO
- = 0x800,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_MAX = 0x1000,
-};
-
-/** android.scaler.availableRecommendedStreamConfigurations enumeration values added since v3.4
- * @see ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS
- */
-enum CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations :
- @3.4::CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations {
- ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_10BIT_OUTPUT
- = 0x8,
- ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8
- = 0x9,
-};
-
-/** android.scaler.availableStreamUseCases enumeration values
- * @see ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES
- */
-enum CameraMetadataEnumAndroidScalerAvailableStreamUseCases : int64_t {
- ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0x0,
- ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 0x1,
- ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 0x2,
- ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3,
- ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL
- = 0x4,
- ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5,
- ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 0x10000,
-};
-
-/** android.automotive.location enumeration values
- * @see ANDROID_AUTOMOTIVE_LOCATION
- */
-enum CameraMetadataEnumAndroidAutomotiveLocation : uint32_t {
- ANDROID_AUTOMOTIVE_LOCATION_INTERIOR,
- ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_OTHER,
- ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_FRONT,
- ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_REAR,
- ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_LEFT,
- ANDROID_AUTOMOTIVE_LOCATION_EXTERIOR_RIGHT,
- ANDROID_AUTOMOTIVE_LOCATION_EXTRA_OTHER,
- ANDROID_AUTOMOTIVE_LOCATION_EXTRA_FRONT,
- ANDROID_AUTOMOTIVE_LOCATION_EXTRA_REAR,
- ANDROID_AUTOMOTIVE_LOCATION_EXTRA_LEFT,
- ANDROID_AUTOMOTIVE_LOCATION_EXTRA_RIGHT,
-};
-
-/** android.automotive.lens.facing enumeration values
- * @see ANDROID_AUTOMOTIVE_LENS_FACING
- */
-enum CameraMetadataEnumAndroidAutomotiveLensFacing : uint32_t {
- ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_OTHER,
- ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_FRONT,
- ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_REAR,
- ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_LEFT,
- ANDROID_AUTOMOTIVE_LENS_FACING_EXTERIOR_RIGHT,
- ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_OTHER,
- ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_LEFT,
- ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_CENTER,
- ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_1_RIGHT,
- ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_LEFT,
- ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_CENTER,
- ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_2_RIGHT,
- ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_LEFT,
- ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_CENTER,
- ANDROID_AUTOMOTIVE_LENS_FACING_INTERIOR_SEAT_ROW_3_RIGHT,
-};
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 2f24dfd..85e69eb 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -50,9 +50,7 @@
"android.hardware.camera.device@3.5",
"android.hardware.camera.device@3.6",
"android.hardware.camera.device@3.7",
- "android.hardware.camera.device@3.8",
"android.hardware.camera.metadata@3.4",
- "android.hardware.camera.metadata@3.8",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index f89c71d..6866776 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -42,14 +42,9 @@
#include <android/hardware/camera/device/3.6/ICameraDevice.h>
#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.7/ICameraDevice.h>
-#include <android/hardware/camera/device/3.8/ICameraDevice.h>
#include <android/hardware/camera/device/3.7/ICameraDeviceSession.h>
-#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
#include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
-#include <android/hardware/camera/device/3.8/ICameraDeviceCallback.h>
-#include <android/hardware/camera/device/3.8/ICameraDeviceSession.h>
#include <android/hardware/camera/metadata/3.4/types.h>
-#include <android/hardware/camera/metadata/3.8/types.h>
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
#include <android/hardware/camera/provider/2.6/ICameraProvider.h>
@@ -134,10 +129,6 @@
CameraMetadataEnumAndroidSensorInfoColorFilterArrangement;
using ::android::hardware::camera::metadata::V3_4::CameraMetadataTag;
using ::android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
-using ::android::hardware::camera::metadata::V3_8::
- CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap;
-using ::android::hardware::camera::metadata::V3_8::
- CameraMetadataEnumAndroidScalerAvailableStreamUseCases;
using ::android::hardware::camera::provider::V2_4::ICameraProvider;
using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
using ::android::hardware::camera::provider::V2_6::CameraIdAndStreamCombination;
@@ -233,8 +224,7 @@
namespace {
// "device@<version>/legacy/<id>"
- const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
- const int CAMERA_DEVICE_API_VERSION_3_8 = 0x308;
+ const char* kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
const int CAMERA_DEVICE_API_VERSION_3_7 = 0x307;
const int CAMERA_DEVICE_API_VERSION_3_6 = 0x306;
const int CAMERA_DEVICE_API_VERSION_3_5 = 0x305;
@@ -242,19 +232,16 @@
const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303;
const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
- const char *kHAL3_8 = "3.8";
- const char *kHAL3_7 = "3.7";
- const char *kHAL3_6 = "3.6";
- const char *kHAL3_5 = "3.5";
- const char *kHAL3_4 = "3.4";
- const char *kHAL3_3 = "3.3";
- const char *kHAL3_2 = "3.2";
- const char *kHAL1_0 = "1.0";
+ const char* kHAL3_7 = "3.7";
+ const char* kHAL3_6 = "3.6";
+ const char* kHAL3_5 = "3.5";
+ const char* kHAL3_4 = "3.4";
+ const char* kHAL3_3 = "3.3";
+ const char* kHAL3_2 = "3.2";
+ const char* kHAL1_0 = "1.0";
- bool matchDeviceName(const hidl_string& deviceName,
- const hidl_string &providerType,
- std::string* deviceVersion,
- std::string* cameraId) {
+ bool matchDeviceName(const hidl_string& deviceName, const hidl_string& providerType,
+ std::string* deviceVersion, std::string* cameraId) {
::android::String8 pattern;
pattern.appendFormat(kDeviceNameRE, providerType.c_str());
std::regex e(pattern.string());
@@ -280,9 +267,7 @@
return -1;
}
- if (version.compare(kHAL3_8) == 0) {
- return CAMERA_DEVICE_API_VERSION_3_8;
- } else if (version.compare(kHAL3_7) == 0) {
+ if (version.compare(kHAL3_7) == 0) {
return CAMERA_DEVICE_API_VERSION_3_7;
} else if (version.compare(kHAL3_6) == 0) {
return CAMERA_DEVICE_API_VERSION_3_6;
@@ -652,7 +637,8 @@
}
virtual Return<void> processCaptureResult_3_4(
- const hidl_vec<V3_4::CaptureResult>& /*results*/) override {
+
+ const hidl_vec<V3_4::CaptureResult>& /*results*/) override {
ALOGI("processCaptureResult_3_4 callback");
ADD_FAILURE(); // Empty callback should not reach here
return Void();
@@ -682,44 +668,41 @@
}
};
- struct DeviceCb : public V3_8::ICameraDeviceCallback {
- DeviceCb(CameraHidlTest *parent, int deviceVersion, const camera_metadata_t *staticMeta) :
- mParent(parent), mDeviceVersion(deviceVersion) {
+ struct DeviceCb : public V3_5::ICameraDeviceCallback {
+ DeviceCb(CameraHidlTest* parent, int deviceVersion, const camera_metadata_t* staticMeta)
+ : mParent(parent), mDeviceVersion(deviceVersion) {
mStaticMetadata = staticMeta;
}
- Return<void> processCaptureResult_3_4(
- const hidl_vec<V3_4::CaptureResult>& results) override;
+ Return<void> processCaptureResult_3_4(const hidl_vec<V3_4::CaptureResult>& results) override;
Return<void> processCaptureResult(const hidl_vec<CaptureResult>& results) override;
Return<void> notify(const hidl_vec<NotifyMsg>& msgs) override;
- Return<void> notify_3_8(const hidl_vec<V3_8::NotifyMsg>& msgs) override;
- Return<void> requestStreamBuffers(
- const hidl_vec<V3_5::BufferRequest>& bufReqs,
- requestStreamBuffers_cb _hidl_cb) override;
+ Return<void> requestStreamBuffers(const hidl_vec<V3_5::BufferRequest>& bufReqs,
+ requestStreamBuffers_cb _hidl_cb) override;
Return<void> returnStreamBuffers(const hidl_vec<StreamBuffer>& buffers) override;
void setCurrentStreamConfig(const hidl_vec<V3_4::Stream>& streams,
- const hidl_vec<V3_2::HalStream>& halStreams);
+ const hidl_vec<V3_2::HalStream>& halStreams);
void waitForBuffersReturned();
private:
bool processCaptureResultLocked(const CaptureResult& results,
- hidl_vec<PhysicalCameraMetadata> physicalCameraMetadata);
+ hidl_vec<PhysicalCameraMetadata> physicalCameraMetadata);
Return<void> notifyHelper(const hidl_vec<NotifyMsg>& msgs,
- const std::vector<std::pair<bool, nsecs_t>>& readoutTimestamps);
+ const std::vector<std::pair<bool, nsecs_t>>& readoutTimestamps);
- CameraHidlTest *mParent; // Parent object
+ CameraHidlTest* mParent; // Parent object
int mDeviceVersion;
android::hardware::camera::common::V1_0::helper::CameraMetadata mStaticMetadata;
bool hasOutstandingBuffersLocked();
/* members for requestStreamBuffers() and returnStreamBuffers()*/
- std::mutex mLock; // protecting members below
- bool mUseHalBufManager = false;
- hidl_vec<V3_4::Stream> mStreams;
+ std::mutex mLock; // protecting members below
+ bool mUseHalBufManager = false;
+ hidl_vec<V3_4::Stream> mStreams;
hidl_vec<V3_2::HalStream> mHalStreams;
uint64_t mNextBufferId = 1;
using OutstandingBuffers = std::unordered_map<uint64_t, hidl_handle>;
@@ -814,20 +797,18 @@
sp<provider::V2_5::ICameraProvider>* provider2_5 /*out*/,
sp<provider::V2_6::ICameraProvider>* provider2_6 /*out*/,
sp<provider::V2_7::ICameraProvider>* provider2_7 /*out*/);
- void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
- sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
- sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
- sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
- sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/,
- sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/,
- sp<device::V3_8::ICameraDeviceSession> *session3_8 /*out*/);
+ void castSession(const sp<ICameraDeviceSession>& session, int32_t deviceVersion,
+ sp<device::V3_3::ICameraDeviceSession>* session3_3 /*out*/,
+ sp<device::V3_4::ICameraDeviceSession>* session3_4 /*out*/,
+ sp<device::V3_5::ICameraDeviceSession>* session3_5 /*out*/,
+ sp<device::V3_6::ICameraDeviceSession>* session3_6 /*out*/,
+ sp<device::V3_7::ICameraDeviceSession>* session3_7 /*out*/);
void castInjectionSession(
const sp<ICameraDeviceSession>& session,
sp<device::V3_7::ICameraInjectionSession>* injectionSession3_7 /*out*/);
void castDevice(const sp<device::V3_2::ICameraDevice>& device, int32_t deviceVersion,
sp<device::V3_5::ICameraDevice>* device3_5 /*out*/,
- sp<device::V3_7::ICameraDevice>* device3_7 /*out*/,
- sp<device::V3_8::ICameraDevice>* device3_8 /*out*/);
+ sp<device::V3_7::ICameraDevice>* device3_7 /*out*/);
void createStreamConfiguration(
const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
StreamConfigurationMode configMode,
@@ -857,16 +838,6 @@
uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
bool maxResolution);
- void configureStreams3_8(const std::string& name, int32_t deviceVersion,
- sp<ICameraProvider> provider, PixelFormat format,
- sp<device::V3_8::ICameraDeviceSession>* session3_8 /*out*/,
- V3_2::Stream* previewStream /*out*/,
- device::V3_6::HalStreamConfiguration* halStreamConfig /*out*/,
- bool* supportsPartialResults /*out*/,
- uint32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
- sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
- bool maxResolution,
- CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap prof);
void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
sp<ICameraProvider> provider,
@@ -947,9 +918,6 @@
static bool isDepthOnly(const camera_metadata_t* staticMeta);
static bool isUltraHighResolution(const camera_metadata_t* staticMeta);
- static void get10BitDynamicRangeProfiles(const camera_metadata_t* staticMeta,
- std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> *profiles);
- static bool is10BitDynamicRangeCapable(const camera_metadata_t* staticMeta);
static Status getAvailableOutputStreams(const camera_metadata_t* staticMeta,
std::vector<AvailableStream>& outputStreams,
@@ -1130,10 +1098,6 @@
expectedPhysicalResults(extraPhysicalResult) {}
};
- static void verify10BitMetadata(HandleImporter& importer,
- const InFlightRequest& request,
- CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap profile);
-
// Map from frame number to the in-flight request state
typedef ::android::KeyedVector<uint32_t, InFlightRequest*> InFlightMap;
@@ -1564,32 +1528,6 @@
}
}
-Return<void> CameraHidlTest::DeviceCb::notify_3_8(
- const hidl_vec<V3_8::NotifyMsg>& msgs) {
- hidl_vec<NotifyMsg> msgs3_2;
- std::vector<std::pair<bool, nsecs_t>> readoutTimestamps;
-
- nsecs_t count = msgs.size();
- msgs3_2.resize(count);
- readoutTimestamps.resize(count);
-
- for (size_t i = 0; i < count; i++) {
- msgs3_2[i].type = msgs[i].type;
- switch (msgs[i].type) {
- case MsgType::ERROR:
- msgs3_2[i].msg.error = msgs[i].msg.error;
- readoutTimestamps[i] = {false, 0};
- break;
- case MsgType::SHUTTER:
- msgs3_2[i].msg.shutter = msgs[i].msg.shutter.v3_2;
- readoutTimestamps[i] = {true, msgs[i].msg.shutter.readoutTimestamp};
- break;
- }
- }
-
- return notifyHelper(msgs3_2, readoutTimestamps);
-}
-
Return<void> CameraHidlTest::DeviceCb::notify(
const hidl_vec<NotifyMsg>& messages) {
std::vector<std::pair<bool, nsecs_t>> readoutTimestamps;
@@ -2082,7 +2020,6 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
case CAMERA_DEVICE_API_VERSION_3_7:
case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
@@ -2127,7 +2064,6 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
case CAMERA_DEVICE_API_VERSION_3_7:
case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
@@ -2869,7 +2805,6 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
case CAMERA_DEVICE_API_VERSION_3_7:
case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
@@ -2957,7 +2892,6 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
case CAMERA_DEVICE_API_VERSION_3_7:
case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
@@ -3018,137 +2952,6 @@
}
}
-// Verify that the torch strength level can be set and retrieved successfully.
-TEST_P(CameraHidlTest, turnOnTorchWithStrengthLevel) {
- hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
- bool torchControlSupported = false;
- bool torchStrengthControlSupported = false;
- Return<void> ret;
-
- ret = mProvider->isSetTorchModeSupported([&](auto status, bool support) {
- ALOGI("isSetTorchModeSupported returns status:%d supported:%d", (int)status, support);
- ASSERT_EQ(Status::OK, status);
- torchControlSupported = support;
- });
-
- sp<TorchProviderCb> cb = new TorchProviderCb(this);
- Return<Status> returnStatus = mProvider->setCallback(cb);
- ASSERT_TRUE(returnStatus.isOk());
- ASSERT_EQ(Status::OK, returnStatus);
-
- for (const auto& name : cameraDeviceNames) {
- int deviceVersion = getCameraDeviceVersion(name, mProviderType);
- int32_t defaultLevel;
- switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8: {
- ::android::sp<::android::hardware::camera::device::V3_8::ICameraDevice> device3_8;
- ALOGI("%s: Testing camera device %s", __FUNCTION__, name.c_str());
- ret = mProvider->getCameraDeviceInterface_V3_x(
- name, [&](auto status, const auto& device) {
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- auto castResult = device::V3_8::ICameraDevice::castFrom(device);
- ASSERT_TRUE(castResult.isOk());
- device3_8 = castResult;
- });
- ASSERT_TRUE(ret.isOk());
-
- ret = device3_8->getCameraCharacteristics([&] (auto s, const auto& chars) {
- ASSERT_EQ(Status::OK, s);
- const camera_metadata_t* staticMeta =
- reinterpret_cast<const camera_metadata_t*>(chars.data());
- ASSERT_NE(nullptr, staticMeta);
- torchStrengthControlSupported = isTorchStrengthControlSupported(staticMeta);
- camera_metadata_ro_entry entry;
- int rc = find_camera_metadata_ro_entry(staticMeta,
- ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL, &entry);
- if (torchStrengthControlSupported) {
- ASSERT_EQ(rc, 0);
- ASSERT_GT(entry.count, 0);
- defaultLevel = *entry.data.i32;
- ALOGI("Default level is:%d", defaultLevel);
- }
- });
- ASSERT_TRUE(ret.isOk());
- // If torchStrengthControl is supported, torchControlSupported should be true.
- if (torchStrengthControlSupported) {
- ASSERT_TRUE(torchControlSupported);
- }
- mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
- returnStatus = device3_8->turnOnTorchWithStrengthLevel(2);
- ASSERT_TRUE(returnStatus.isOk());
- // Method_not_supported check
- if (!torchStrengthControlSupported) {
- ALOGI("Torch strength control not supported.");
- ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, returnStatus);
- } else {
- ASSERT_EQ(Status::OK, returnStatus);
- if (returnStatus == Status::OK) {
- {
- std::unique_lock<std::mutex> l(mTorchLock);
- while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
- auto timeout = std::chrono::system_clock::now() +
- std::chrono::seconds(kTorchTimeoutSec);
- ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l,
- timeout));
- }
- ASSERT_EQ(TorchModeStatus::AVAILABLE_ON, mTorchStatus);
- mTorchStatus = TorchModeStatus::NOT_AVAILABLE;
- }
- ALOGI("getTorchStrengthLevel: Testing");
- ret = device3_8->getTorchStrengthLevel([&]
- (auto status, const auto& strengthLevel) {
- ASSERT_TRUE(ret.isOk());
- ASSERT_EQ(Status::OK, status);
- ALOGI("Torch strength level is : %d", strengthLevel);
- ASSERT_EQ(strengthLevel, 2);
- });
- // Turn OFF the torch and verify torch strength level is reset to default level.
- ALOGI("Testing torch strength level reset after turning the torch OFF.");
- returnStatus = device3_8->setTorchMode(TorchMode::OFF);
- ASSERT_TRUE(returnStatus.isOk());
- ASSERT_EQ(Status::OK, returnStatus);
- {
- std::unique_lock<std::mutex> l(mTorchLock);
- while (TorchModeStatus::NOT_AVAILABLE == mTorchStatus) {
- auto timeout = std::chrono::system_clock::now() +
- std::chrono::seconds(kTorchTimeoutSec);
- ASSERT_NE(std::cv_status::timeout, mTorchCond.wait_until(l,
- timeout));
- }
- ASSERT_EQ(TorchModeStatus::AVAILABLE_OFF, mTorchStatus);
- }
- ret = device3_8->getTorchStrengthLevel([&]
- (auto status, const auto& strengthLevel) {
- ASSERT_TRUE(ret.isOk());
- ASSERT_EQ(Status::OK, status);
- ALOGI("Torch strength level after turning OFF torch is : %d",
- strengthLevel);
- ASSERT_EQ(strengthLevel, defaultLevel);
- });
- }
- }
- }
- break;
- case CAMERA_DEVICE_API_VERSION_3_7:
- case CAMERA_DEVICE_API_VERSION_3_6:
- case CAMERA_DEVICE_API_VERSION_3_5:
- case CAMERA_DEVICE_API_VERSION_3_4:
- case CAMERA_DEVICE_API_VERSION_3_3:
- case CAMERA_DEVICE_API_VERSION_3_2:
- case CAMERA_DEVICE_API_VERSION_1_0: {
- ALOGI("Torch strength control feature not supported.");
- }
- break;
- default: {
- ALOGI("Invalid device version.");
- ADD_FAILURE();
- }
- break;
- }
- }
-}
-
//In case it is supported verify that torch can be enabled.
//Check for corresponding toch callbacks as well.
TEST_P(CameraHidlTest, setTorchMode) {
@@ -3170,7 +2973,6 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
case CAMERA_DEVICE_API_VERSION_3_7:
case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
@@ -3299,7 +3101,6 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
case CAMERA_DEVICE_API_VERSION_3_7:
case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
@@ -3367,7 +3168,6 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
case CAMERA_DEVICE_API_VERSION_3_7:
case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
@@ -3401,13 +3201,10 @@
sp<device::V3_5::ICameraDeviceSession> sessionV3_5;
sp<device::V3_6::ICameraDeviceSession> sessionV3_6;
sp<device::V3_7::ICameraDeviceSession> sessionV3_7;
- sp<device::V3_8::ICameraDeviceSession> sessionV3_8;
- castSession(session, deviceVersion, &sessionV3_3,
- &sessionV3_4, &sessionV3_5, &sessionV3_6,
- &sessionV3_7, &sessionV3_8);
- if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_8) {
- ASSERT_TRUE(sessionV3_8.get() != nullptr);
- } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_7) {
+ castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4, &sessionV3_5,
+ &sessionV3_6, &sessionV3_7);
+
+ if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_7) {
ASSERT_TRUE(sessionV3_7.get() != nullptr);
} else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) {
ASSERT_TRUE(sessionV3_6.get() != nullptr);
@@ -3417,7 +3214,7 @@
ASSERT_TRUE(sessionV3_4.get() != nullptr);
} else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_3) {
ASSERT_TRUE(sessionV3_3.get() != nullptr);
- } else { //V3_2
+ } else { // V3_2
ASSERT_TRUE(sessionV3_3.get() == nullptr);
ASSERT_TRUE(sessionV3_4.get() == nullptr);
ASSERT_TRUE(sessionV3_5.get() == nullptr);
@@ -3473,7 +3270,6 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8:
case CAMERA_DEVICE_API_VERSION_3_7:
case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
@@ -3575,17 +3371,14 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider,
&session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
- &cameraDevice3_8);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+ &session3_7);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
outputStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -3681,11 +3474,9 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8;
::android::hardware::camera::device::V3_7::StreamConfiguration config3_7;
::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
@@ -3722,9 +3513,8 @@
openEmptyDeviceSession(name, mProvider2_6, &cti.session /*out*/,
&cti.staticMeta /*out*/, &cti.cameraDevice /*out*/);
castSession(cti.session, deviceVersion, &cti.session3_3, &cti.session3_4,
- &cti.session3_5, &cti.session3_6, &cti.session3_7, &cti.session3_8);
- castDevice(cti.cameraDevice, deviceVersion, &cti.cameraDevice3_5, &cti.cameraDevice3_7,
- &cti.cameraDevice3_8);
+ &cti.session3_5, &cti.session3_6, &cti.session3_7);
+ castDevice(cti.cameraDevice, deviceVersion, &cti.cameraDevice3_5, &cti.cameraDevice3_7);
outputStreams.clear();
ASSERT_EQ(Status::OK, getMandatoryConcurrentStreams(cti.staticMeta, &outputStreams));
@@ -3853,17 +3643,14 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
- &cameraDevice3_8);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+ &session3_7);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
outputStreams.clear();
ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams));
@@ -4069,17 +3856,14 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
- &cameraDevice3_8);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+ &session3_7);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
Status rc = isZSLModeAvailable(staticMeta);
if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -4258,10 +4042,9 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+ &session3_7);
if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
ASSERT_NE(session3_4, nullptr);
} else {
@@ -4400,17 +4183,14 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
- &cameraDevice3_8);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+ &session3_7);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
// Check if camera support depth only
if (isDepthOnly(staticMeta)) {
@@ -4537,17 +4317,14 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
- &cameraDevice3_8);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+ &session3_7);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
Status rc = isConstrainedModeAvailable(staticMeta);
if (Status::METHOD_NOT_SUPPORTED == rc) {
@@ -4820,17 +4597,14 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
- &cameraDevice3_8);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+ &session3_7);
+ castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
// Check if camera support depth only
if (isDepthOnly(staticMeta)) {
@@ -5069,28 +4843,6 @@
ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
- // For camera device 3.8 or newer, shutterReadoutTimestamp must be
- // available, and it must be >= shutterTimestamp + exposureTime, and
- // < shutterTimestamp + exposureTime + rollingShutterSkew / 2.
- if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8) {
- ASSERT_TRUE(inflightReq.shutterReadoutTimestampValid);
- ASSERT_FALSE(inflightReq.collectedResult.isEmpty());
- if (inflightReq.collectedResult.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
- camera_metadata_entry_t exposureTimeResult = inflightReq.collectedResult.find(
- ANDROID_SENSOR_EXPOSURE_TIME);
- nsecs_t exposureToReadout =
- inflightReq.shutterReadoutTimestamp - inflightReq.shutterTimestamp;
- ASSERT_GE(exposureToReadout, exposureTimeResult.data.i64[0]);
- if (inflightReq.collectedResult.exists(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW)) {
- camera_metadata_entry_t rollingShutterSkew =
- inflightReq.collectedResult.find(
- ANDROID_SENSOR_ROLLING_SHUTTER_SKEW);
- ASSERT_LT(exposureToReadout, exposureTimeResult.data.i64[0] +
- rollingShutterSkew.data.i64[0] / 2);
- }
- }
- }
-
request.frameNumber++;
// Empty settings should be supported after the first call
// for repeating requests.
@@ -5114,20 +4866,6 @@
ASSERT_EQ(Status::OK, status);
ASSERT_EQ(numRequestProcessed, 1u);
- if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8) {
- sp<device::V3_3::ICameraDeviceSession> session3_3;
- sp<device::V3_4::ICameraDeviceSession> session3_4;
- sp<device::V3_5::ICameraDeviceSession> session3_5;
- sp<device::V3_6::ICameraDeviceSession> session3_6;
- sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
- ASSERT_TRUE(session3_8.get() != nullptr);
- hidl_vec<int32_t> streamIds = { halStreamConfig.streams[0].id };
- session3_8->repeatingRequestEnd(request.frameNumber, streamIds);
- }
-
{
std::unique_lock<std::mutex> l(mLock);
while (!inflightReq.errorCodeValid &&
@@ -5153,196 +4891,6 @@
}
}
-TEST_P(CameraHidlTest, processCaptureRequestPreviewStabilization) {
- std::unordered_map<std::string, nsecs_t> cameraDeviceToTimeLag;
- processPreviewStabilizationCaptureRequestInternal(/*previewStabilizationOn*/ false,
- cameraDeviceToTimeLag);
- processPreviewStabilizationCaptureRequestInternal(/*previewStabilizationOn*/ true,
- cameraDeviceToTimeLag);
-}
-
-void CameraHidlTest::processPreviewStabilizationCaptureRequestInternal(
- bool previewStabilizationOn,
- // Used as output when preview stabilization is off, as output when its
- // on.
- std::unordered_map<std::string, nsecs_t>& cameraDeviceToTimeLag) {
- hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
- AvailableStream streamThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
- static_cast<int32_t>(PixelFormat::IMPLEMENTATION_DEFINED)};
- uint64_t bufferId = 1;
- uint32_t frameNumber = 1;
- ::android::hardware::hidl_vec<uint8_t> settings;
-
- for (const auto& name : cameraDeviceNames) {
- int deviceVersion = getCameraDeviceVersion(name, mProviderType);
- if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
- continue;
- } else if (deviceVersion <= 0) {
- ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
- ADD_FAILURE();
- return;
- }
-
- if (!supportsPreviewStabilization(name, mProvider)) {
- ALOGI(" %s Camera device %s doesn't support preview stabilization, skipping", __func__,
- name.c_str());
- continue;
- }
-
- if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
- ALOGE("%s: device version < 3.8 must not advertise preview stabilization,"
- " camera metadata validation will fail",
- __func__);
- ADD_FAILURE();
- }
-
- V3_2::Stream testStream;
- HalStreamConfiguration halStreamConfig;
- sp<ICameraDeviceSession> session;
- sp<DeviceCb> cb;
- bool supportsPartialResults = false;
- bool useHalBufManager = false;
- uint32_t partialResultCount = 0;
- configureSingleStream(name, deviceVersion, mProvider, &streamThreshold,
- GRALLOC1_CONSUMER_USAGE_HWCOMPOSER, RequestTemplate::PREVIEW,
- &session /*out*/, &testStream /*out*/, &halStreamConfig /*out*/,
- &supportsPartialResults /*out*/, &partialResultCount /*out*/,
- &useHalBufManager /*out*/, &cb /*out*/);
-
- std::shared_ptr<ResultMetadataQueue> resultQueue;
- auto resultQueueRet =
- session->getCaptureResultMetadataQueue([&resultQueue](const auto& descriptor) {
- 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.
- }
- });
- ASSERT_TRUE(resultQueueRet.isOk());
-
- InFlightRequest inflightReq = {1, false, supportsPartialResults, partialResultCount,
- resultQueue};
-
- Return<void> ret;
- android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
- ret = session->constructDefaultRequestSettings(
- RequestTemplate::PREVIEW, [&](auto status, const auto& req) {
- ASSERT_EQ(Status::OK, status);
- const camera_metadata_t* metadata =
- reinterpret_cast<const camera_metadata_t*>(req.data());
- defaultSettings = metadata;
- settings = req;
- });
- ASSERT_TRUE(ret.isOk());
- android::status_t metadataRet = ::android::OK;
- uint8_t videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
- if (previewStabilizationOn) {
- videoStabilizationMode = ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION;
- metadataRet = defaultSettings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
- &videoStabilizationMode, 1);
- } else {
- metadataRet = defaultSettings.update(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
- &videoStabilizationMode, 1);
- }
- ASSERT_EQ(metadataRet, ::android::OK);
- hidl_handle buffer_handle;
- StreamBuffer outputBuffer;
- if (useHalBufManager) {
- outputBuffer = {halStreamConfig.streams[0].id,
- /*bufferId*/ 0,
- buffer_handle,
- BufferStatus::OK,
- nullptr,
- nullptr};
- } else {
- allocateGraphicBuffer(
- testStream.width, testStream.height,
- /* We don't look at halStreamConfig.streams[0].consumerUsage
- * since that is 0 for output streams
- */
- android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
- GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
- halStreamConfig.streams[0].overrideFormat, &buffer_handle);
- outputBuffer = {halStreamConfig.streams[0].id,
- bufferId,
- buffer_handle,
- BufferStatus::OK,
- nullptr,
- nullptr};
- }
- ::android::hardware::hidl_vec<StreamBuffer> outputBuffers = {outputBuffer};
- StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
- CaptureRequest request = {frameNumber, 0 /* fmqSettingsSize */, settings, emptyInputBuffer,
- outputBuffers};
-
- {
- std::unique_lock<std::mutex> l(mLock);
- mInflightMap.clear();
- mInflightMap.add(frameNumber, &inflightReq);
- }
-
- Status status = Status::INTERNAL_ERROR;
- uint32_t numRequestProcessed = 0;
- hidl_vec<BufferCache> cachesToRemove;
- Return<void> returnStatus = session->processCaptureRequest(
- {request}, cachesToRemove, [&status, &numRequestProcessed](auto s, uint32_t n) {
- status = s;
- numRequestProcessed = n;
- });
- ASSERT_TRUE(returnStatus.isOk());
- ASSERT_EQ(Status::OK, status);
- ASSERT_EQ(numRequestProcessed, 1u);
-
- {
- std::unique_lock<std::mutex> l(mLock);
- while (!inflightReq.errorCodeValid &&
- ((0 < inflightReq.numBuffersLeft) || (!inflightReq.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(inflightReq.errorCodeValid);
- ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
- ASSERT_EQ(testStream.id, inflightReq.resultOutputBuffers[0].buffer.streamId);
- ASSERT_TRUE(inflightReq.shutterReadoutTimestampValid);
- nsecs_t readoutTimestamp = inflightReq.shutterReadoutTimestamp;
-
- if (previewStabilizationOn) {
- // Here we collect the time difference between the buffer ready
- // timestamp - notify readout timestamp.
- // timeLag = buffer ready timestamp - notify readout timestamp.
- // timeLag(previewStabilization) must be <=
- // timeLag(stabilization off) + 1 frame duration.
- auto it = cameraDeviceToTimeLag.find(name.c_str());
- camera_metadata_entry e;
- e = inflightReq.collectedResult.find(ANDROID_SENSOR_FRAME_DURATION);
- ASSERT_TRUE(e.count > 0);
- nsecs_t frameDuration = e.data.i64[0];
- ASSERT_TRUE(it != cameraDeviceToTimeLag.end());
-
- nsecs_t previewStabOnLagTime =
- inflightReq.resultOutputBuffers[0].timeStamp - readoutTimestamp;
- ASSERT_TRUE(previewStabOnLagTime <= (it->second + frameDuration));
- } else {
- // Fill in the buffer ready timestamp - notify timestamp;
- cameraDeviceToTimeLag[std::string(name.c_str())] =
- inflightReq.resultOutputBuffers[0].timeStamp - readoutTimestamp;
- }
- }
-
- if (useHalBufManager) {
- verifyBuffersReturned(session, deviceVersion, testStream.id, cb);
- }
-
- ret = session->close();
- ASSERT_TRUE(ret.isOk());
- }
-}
-
// Generate and verify a multi-camera capture request
TEST_P(CameraHidlTest, processMultiCaptureRequestPreview) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
@@ -5771,188 +5319,6 @@
}
}
-// Generate and verify 10-bit dynamic range request
-TEST_P(CameraHidlTest, process10BitDynamicRangeRequest) {
- hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
- uint64_t bufferId = 1;
- uint32_t frameNumber = 1;
- ::android::hardware::hidl_vec<uint8_t> settings;
-
- for (const auto& name : cameraDeviceNames) {
- int deviceVersion = getCameraDeviceVersion(name, mProviderType);
- if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
- continue;
- }
- std::string version, deviceId;
- ASSERT_TRUE(::matchDeviceName(name, mProviderType, &version, &deviceId));
- camera_metadata_t* staticMeta;
- Return<void> ret;
- sp<ICameraDeviceSession> session;
- openEmptyDeviceSession(name, mProvider, &session, &staticMeta);
- if (!is10BitDynamicRangeCapable(staticMeta)) {
- free_camera_metadata(staticMeta);
- ret = session->close();
- ASSERT_TRUE(ret.isOk());
- continue;
- }
- std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> profileList;
- get10BitDynamicRangeProfiles(staticMeta, &profileList);
- ASSERT_FALSE(profileList.empty());
-
- android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
- ret = session->constructDefaultRequestSettings(
- RequestTemplate::STILL_CAPTURE,
- [&defaultSettings](auto status, const auto& req) mutable {
- ASSERT_EQ(Status::OK, status);
-
- const camera_metadata_t* metadata =
- reinterpret_cast<const camera_metadata_t*>(req.data());
- size_t expectedSize = req.size();
- int result = validate_camera_metadata_structure(metadata, &expectedSize);
- ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
-
- size_t entryCount = get_camera_metadata_entry_count(metadata);
- ASSERT_GT(entryCount, 0u);
- defaultSettings = metadata;
- });
- ASSERT_TRUE(ret.isOk());
-
- const camera_metadata_t* settingsBuffer = defaultSettings.getAndLock();
- settings.setToExternal(
- reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(settingsBuffer)),
- get_camera_metadata_size(settingsBuffer));
- overrideRotateAndCrop(&settings);
-
- free_camera_metadata(staticMeta);
- ret = session->close();
- ASSERT_TRUE(ret.isOk());
- V3_6::HalStreamConfiguration halStreamConfig;
- bool supportsPartialResults = false;
- bool useHalBufManager = false;
- uint32_t partialResultCount = 0;
- V3_2::Stream previewStream;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
- sp<DeviceCb> cb;
- for (const auto& profile : profileList) {
- configureStreams3_8(name, deviceVersion, mProvider, PixelFormat::IMPLEMENTATION_DEFINED,
- &session3_8, &previewStream, &halStreamConfig,
- &supportsPartialResults, &partialResultCount, &useHalBufManager,
- &cb, 0, /*maxResolution*/ false, profile);
- ASSERT_NE(session3_8, nullptr);
-
- std::shared_ptr<ResultMetadataQueue> resultQueue;
- auto resultQueueRet = session3_8->getCaptureResultMetadataQueue(
- [&resultQueue](const auto& descriptor) {
- 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.
- }
- });
- ASSERT_TRUE(resultQueueRet.isOk());
-
- std::vector<hidl_handle> graphicBuffers;
- graphicBuffers.reserve(halStreamConfig.streams.size());
- ::android::hardware::hidl_vec<StreamBuffer> outputBuffers;
- outputBuffers.resize(halStreamConfig.streams.size());
- InFlightRequest inflightReq = {static_cast<ssize_t>(halStreamConfig.streams.size()),
- false,
- supportsPartialResults,
- partialResultCount,
- std::unordered_set<std::string>(),
- resultQueue};
-
- size_t k = 0;
- for (const auto& halStream : halStreamConfig.streams) {
- hidl_handle buffer_handle;
- if (useHalBufManager) {
- outputBuffers[k] = {halStream.v3_4.v3_3.v3_2.id,
- 0,
- buffer_handle,
- BufferStatus::OK,
- nullptr,
- nullptr};
- } else {
- allocateGraphicBuffer(
- previewStream.width, previewStream.height,
- android_convertGralloc1To0Usage(halStream.v3_4.v3_3.v3_2.producerUsage,
- halStream.v3_4.v3_3.v3_2.consumerUsage),
- halStream.v3_4.v3_3.v3_2.overrideFormat, &buffer_handle);
-
- graphicBuffers.push_back(buffer_handle);
- outputBuffers[k] = {halStream.v3_4.v3_3.v3_2.id,
- bufferId,
- buffer_handle,
- BufferStatus::OK,
- nullptr,
- nullptr};
- bufferId++;
- }
- k++;
- }
-
- StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
- V3_4::CaptureRequest request3_4;
- request3_4.v3_2.frameNumber = frameNumber;
- request3_4.v3_2.fmqSettingsSize = 0;
- request3_4.v3_2.settings = settings;
- request3_4.v3_2.inputBuffer = emptyInputBuffer;
- request3_4.v3_2.outputBuffers = outputBuffers;
- V3_7::CaptureRequest request3_7;
- request3_7.v3_4 = request3_4;
- request3_7.inputWidth = 0;
- request3_7.inputHeight = 0;
-
- {
- std::unique_lock<std::mutex> l(mLock);
- mInflightMap.clear();
- mInflightMap.add(frameNumber, &inflightReq);
- }
-
- Status stat = Status::INTERNAL_ERROR;
- uint32_t numRequestProcessed = 0;
- hidl_vec<BufferCache> cachesToRemove;
- Return<void> returnStatus = session3_8->processCaptureRequest_3_7(
- {request3_7}, cachesToRemove,
- [&stat, &numRequestProcessed](auto s, uint32_t n) {
- stat = s;
- numRequestProcessed = n;
- });
- ASSERT_TRUE(returnStatus.isOk());
- ASSERT_EQ(Status::OK, stat);
- ASSERT_EQ(numRequestProcessed, 1u);
-
- {
- std::unique_lock<std::mutex> l(mLock);
- while (!inflightReq.errorCodeValid &&
- ((0 < inflightReq.numBuffersLeft) || (!inflightReq.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(inflightReq.errorCodeValid);
- ASSERT_NE(inflightReq.resultOutputBuffers.size(), 0u);
- verify10BitMetadata(mHandleImporter, inflightReq, profile);
- }
- if (useHalBufManager) {
- hidl_vec<int32_t> streamIds(halStreamConfig.streams.size());
- for (size_t i = 0; i < streamIds.size(); i++) {
- streamIds[i] = halStreamConfig.streams[i].v3_4.v3_3.v3_2.id;
- }
- session3_8->signalStreamFlush(streamIds, /*streamConfigCounter*/ 0);
- cb->waitForBuffersReturned();
- }
-
- ret = session3_8->close();
- ASSERT_TRUE(ret.isOk());
- }
- }
-}
-
// Generate and verify a burst containing alternating sensor sensitivity values
TEST_P(CameraHidlTest, processCaptureRequestBurstISO) {
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
@@ -5982,8 +5348,8 @@
camera_metadata_entry_t hwLevel = staticMeta.find(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL);
ASSERT_TRUE(0 < hwLevel.count);
if (ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED == hwLevel.data.u8[0] ||
- ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL == hwLevel.data.u8[0]) {
- //Limited/External devices can skip this test
+ ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL == hwLevel.data.u8[0]) {
+ // Limited/External devices can skip this test
ret = session->close();
ASSERT_TRUE(ret.isOk());
continue;
@@ -6946,134 +6312,6 @@
}
}
-// Verify that valid stream use cases can be configured successfully, and invalid use cases
-// fail stream configuration.
-TEST_P(CameraHidlTest, configureStreamsUseCases) {
- hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-
- for (const auto& name : cameraDeviceNames) {
- int deviceVersion = getCameraDeviceVersion(name, mProviderType);
- if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_8) {
- continue;
- }
-
- camera_metadata_t* staticMeta;
- Return<void> ret;
- sp<ICameraDeviceSession> session;
- sp<device::V3_3::ICameraDeviceSession> session3_3;
- sp<device::V3_4::ICameraDeviceSession> session3_4;
- sp<device::V3_5::ICameraDeviceSession> session3_5;
- sp<device::V3_6::ICameraDeviceSession> session3_6;
- sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
- sp<device::V3_2::ICameraDevice> cameraDevice;
- sp<device::V3_5::ICameraDevice> cameraDevice3_5;
- sp<device::V3_7::ICameraDevice> cameraDevice3_7;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8;
- openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
- &cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
- ASSERT_NE(nullptr, session3_8);
- castDevice(cameraDevice, deviceVersion, &cameraDevice3_5, &cameraDevice3_7,
- &cameraDevice3_8);
- ASSERT_NE(nullptr, cameraDevice3_8);
-
- // Check if camera support depth only
- if (isDepthOnly(staticMeta)) {
- free_camera_metadata(staticMeta);
- ret = session->close();
- ASSERT_TRUE(ret.isOk());
- continue;
- }
-
- std::vector<AvailableStream> outputPreviewStreams;
- AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
- static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
- ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputPreviewStreams,
- &previewThreshold));
- ASSERT_NE(0u, outputPreviewStreams.size());
-
- // Combine valid and invalid stream use cases
- std::vector<int64_t> useCases(kMandatoryUseCases);
- useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL + 1);
-
- std::vector<int64_t> supportedUseCases;
- camera_metadata_ro_entry entry;
- auto retcode = find_camera_metadata_ro_entry(staticMeta,
- ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
- if ((0 == retcode) && (entry.count > 0)) {
- supportedUseCases.insert(supportedUseCases.end(), entry.data.i64,
- entry.data.i64 + entry.count);
- } else {
- supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
- }
- free_camera_metadata(staticMeta);
-
- ::android::hardware::hidl_vec<V3_8::Stream> streams3_8(1);
- streams3_8[0].v3_7.groupId = -1;
- streams3_8[0].v3_7.sensorPixelModesUsed = {
- CameraMetadataEnumAndroidSensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT};
- streams3_8[0].v3_7.v3_4.bufferSize = 0;
- streams3_8[0].v3_7.v3_4.v3_2.id = 0;
- streams3_8[0].v3_7.v3_4.v3_2.streamType = StreamType::OUTPUT;
- streams3_8[0].v3_7.v3_4.v3_2.width = static_cast<uint32_t>(outputPreviewStreams[0].width);
- streams3_8[0].v3_7.v3_4.v3_2.height = static_cast<uint32_t>(outputPreviewStreams[0].height);
- streams3_8[0].v3_7.v3_4.v3_2.format =
- static_cast<PixelFormat>(outputPreviewStreams[0].format);
- streams3_8[0].v3_7.v3_4.v3_2.usage = GRALLOC1_CONSUMER_USAGE_CPU_READ;
- streams3_8[0].v3_7.v3_4.v3_2.dataSpace = 0;
- streams3_8[0].v3_7.v3_4.v3_2.rotation = StreamRotation::ROTATION_0;
- streams3_8[0].dynamicRangeProfile =
- static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>(
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
-
- uint32_t streamConfigCounter = 0;
- ::android::hardware::camera::device::V3_8::StreamConfiguration config3_8;
- RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
- ret = session3_8->constructDefaultRequestSettings(reqTemplate,
- [&config3_8](auto status, const auto& req) {
- ASSERT_EQ(Status::OK, status);
- config3_8.sessionParams = req;
- });
- ASSERT_TRUE(ret.isOk());
-
- for (int64_t useCase : useCases) {
- bool useCaseSupported = std::find(supportedUseCases.begin(),
- supportedUseCases.end(), useCase) != supportedUseCases.end();
-
- streams3_8[0].useCase =
- static_cast<CameraMetadataEnumAndroidScalerAvailableStreamUseCases>(useCase);
- config3_8.streams = streams3_8;
- config3_8.operationMode = StreamConfigurationMode::NORMAL_MODE;
- config3_8.streamConfigCounter = streamConfigCounter;
- config3_8.multiResolutionInputImage = false;
- ret = cameraDevice3_8->isStreamCombinationSupported_3_8(
- config3_8, [&useCaseSupported](Status s, bool combStatus) {
- ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s));
- if (Status::OK == s) {
- ASSERT_EQ(combStatus, useCaseSupported);
- }
- });
- ASSERT_TRUE(ret.isOk());
-
- ret = session3_8->configureStreams_3_8(
- config3_8,
- [&](Status s, device::V3_6::HalStreamConfiguration halConfig) {
- if (useCaseSupported) {
- ASSERT_EQ(Status::OK, s);
- ASSERT_EQ(1u, halConfig.streams.size());
- } else {
- ASSERT_EQ(Status::ILLEGAL_ARGUMENT, s);
- }
- });
- ASSERT_TRUE(ret.isOk());
- }
- ret = session3_8->close();
- ASSERT_TRUE(ret.isOk());
- }
-}
-
// Retrieve all valid output stream resolutions from the camera
// static characteristics.
Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
@@ -7736,9 +6974,8 @@
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
- session3_7, &session3_8);
+ session3_7);
ASSERT_NE(nullptr, (*session3_7).get());
*useHalBufManager = false;
@@ -7786,8 +7023,7 @@
ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_7);
sp<device::V3_5::ICameraDevice> cameraDevice3_5 = nullptr;
sp<device::V3_7::ICameraDevice> cameraDevice3_7 = nullptr;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8 = nullptr;
- castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
+ castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
ASSERT_NE(cameraDevice3_7, nullptr);
bool supported = false;
ret = cameraDevice3_7->isStreamCombinationSupported_3_7(
@@ -7820,153 +7056,6 @@
ASSERT_TRUE(ret.isOk());
}
-// Configure streams
-void CameraHidlTest::configureStreams3_8(
- const std::string& name, int32_t deviceVersion, sp<ICameraProvider> provider,
- PixelFormat format, sp<device::V3_8::ICameraDeviceSession>* session3_8 /*out*/,
- V3_2::Stream* previewStream /*out*/,
- device::V3_6::HalStreamConfiguration* halStreamConfig /*out*/,
- bool* supportsPartialResults /*out*/, uint32_t* partialResultCount /*out*/,
- bool* useHalBufManager /*out*/, sp<DeviceCb>* outCb /*out*/, uint32_t streamConfigCounter,
- bool maxResolution,
- CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap prof) {
- ASSERT_NE(nullptr, session3_8);
- ASSERT_NE(nullptr, halStreamConfig);
- ASSERT_NE(nullptr, previewStream);
- ASSERT_NE(nullptr, supportsPartialResults);
- ASSERT_NE(nullptr, partialResultCount);
- ASSERT_NE(nullptr, useHalBufManager);
- ASSERT_NE(nullptr, outCb);
- ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_8);
-
- std::vector<AvailableStream> outputStreams;
- ::android::sp<ICameraDevice> device3_x;
- ALOGI("configureStreams: Testing camera device %s", name.c_str());
- Return<void> ret;
- ret = provider->getCameraDeviceInterface_V3_x(name, [&](auto status, const auto& device) {
- ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(device, nullptr);
- device3_x = device;
- });
- ASSERT_TRUE(ret.isOk());
-
- camera_metadata_t* staticMeta;
- ret = device3_x->getCameraCharacteristics([&](Status s, CameraMetadata metadata) {
- ASSERT_EQ(Status::OK, s);
- staticMeta =
- clone_camera_metadata(reinterpret_cast<const camera_metadata_t*>(metadata.data()));
- ASSERT_NE(nullptr, staticMeta);
- });
- ASSERT_TRUE(ret.isOk());
-
- camera_metadata_ro_entry entry;
- auto status =
- find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
- if ((0 == status) && (entry.count > 0)) {
- *partialResultCount = entry.data.i32[0];
- *supportsPartialResults = (*partialResultCount > 1);
- }
-
- sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta);
- sp<ICameraDeviceSession> session;
- ret = device3_x->open(cb, [&session](auto status, const auto& newSession) {
- ALOGI("device::open returns status:%d", (int)status);
- ASSERT_EQ(Status::OK, status);
- ASSERT_NE(newSession, nullptr);
- session = newSession;
- });
- ASSERT_TRUE(ret.isOk());
- *outCb = cb;
-
- sp<device::V3_3::ICameraDeviceSession> session3_3;
- sp<device::V3_4::ICameraDeviceSession> session3_4;
- sp<device::V3_5::ICameraDeviceSession> session3_5;
- sp<device::V3_6::ICameraDeviceSession> session3_6;
- sp<device::V3_7::ICameraDeviceSession> session3_7;
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
- &session3_7, session3_8);
- ASSERT_NE(nullptr, (*session3_8).get());
-
- *useHalBufManager = false;
- status = find_camera_metadata_ro_entry(
- staticMeta, ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
- if ((0 == status) && (entry.count == 1)) {
- *useHalBufManager = (entry.data.u8[0] ==
- ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
- }
-
- outputStreams.clear();
- Size maxSize;
- auto rc = getMaxOutputSizeForFormat(staticMeta, format, &maxSize, maxResolution);
- ASSERT_EQ(Status::OK, rc);
- free_camera_metadata(staticMeta);
-
- ::android::hardware::hidl_vec<V3_8::Stream> streams3_8(1);
- streams3_8[0].v3_7.groupId = -1;
- streams3_8[0].v3_7.sensorPixelModesUsed = {
- CameraMetadataEnumAndroidSensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT};
- streams3_8[0].v3_7.v3_4.bufferSize = 0;
- streams3_8[0].v3_7.v3_4.v3_2.id = 0;
- streams3_8[0].v3_7.v3_4.v3_2.streamType = StreamType::OUTPUT;
- streams3_8[0].v3_7.v3_4.v3_2.width = static_cast<uint32_t>(maxSize.width);
- streams3_8[0].v3_7.v3_4.v3_2.height = static_cast<uint32_t>(maxSize.height);
- streams3_8[0].v3_7.v3_4.v3_2.format = static_cast<PixelFormat>(format);
- streams3_8[0].v3_7.v3_4.v3_2.usage = GRALLOC1_CONSUMER_USAGE_CPU_READ;
- streams3_8[0].v3_7.v3_4.v3_2.dataSpace = 0;
- streams3_8[0].v3_7.v3_4.v3_2.rotation = StreamRotation::ROTATION_0;
- streams3_8[0].dynamicRangeProfile = prof;
-
- ::android::hardware::camera::device::V3_8::StreamConfiguration config3_8;
- config3_8.streams = streams3_8;
- config3_8.operationMode = StreamConfigurationMode::NORMAL_MODE;
- config3_8.streamConfigCounter = streamConfigCounter;
- config3_8.multiResolutionInputImage = false;
- RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
- ret = (*session3_8)
- ->constructDefaultRequestSettings(reqTemplate,
- [&config3_8](auto status, const auto& req) {
- ASSERT_EQ(Status::OK, status);
- config3_8.sessionParams = req;
- });
- ASSERT_TRUE(ret.isOk());
-
- sp<device::V3_5::ICameraDevice> cameraDevice3_5 = nullptr;
- sp<device::V3_7::ICameraDevice> cameraDevice3_7 = nullptr;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8 = nullptr;
- castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
- ASSERT_NE(cameraDevice3_8, nullptr);
- bool supported = false;
- ret = cameraDevice3_8->isStreamCombinationSupported_3_8(
- config3_8, [&supported](Status s, bool combStatus) {
- ASSERT_TRUE((Status::OK == s) || (Status::METHOD_NOT_SUPPORTED == s));
- if (Status::OK == s) {
- supported = combStatus;
- }
- });
- ASSERT_TRUE(ret.isOk());
- ASSERT_EQ(supported, true);
-
- if (*session3_8 != nullptr) {
- ret = (*session3_8)
- ->configureStreams_3_8(
- config3_8,
- [&](Status s, device::V3_6::HalStreamConfiguration halConfig) {
- ASSERT_EQ(Status::OK, s);
- *halStreamConfig = halConfig;
- if (*useHalBufManager) {
- hidl_vec<V3_4::Stream> streams(1);
- hidl_vec<V3_2::HalStream> halStreams(1);
- streams[0] = streams3_8[0].v3_7.v3_4;
- halStreams[0] = halConfig.streams[0].v3_4.v3_3.v3_2;
- cb->setCurrentStreamConfig(streams, halStreams);
- }
- });
- }
- *previewStream = streams3_8[0].v3_7.v3_4.v3_2;
- ASSERT_TRUE(ret.isOk());
-}
-
// Configure multiple preview streams using different physical ids.
void CameraHidlTest::configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
sp<ICameraProvider> provider,
@@ -8041,9 +7130,8 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
- castSession(session, deviceVersion, &session3_3, session3_4, session3_5,
- &session3_6, &session3_7, &session3_8);
+ castSession(session, deviceVersion, &session3_3, session3_4, session3_5, &session3_6,
+ &session3_7);
ASSERT_NE(nullptr, (*session3_4).get());
*useHalBufManager = false;
@@ -8088,8 +7176,7 @@
if (allowUnsupport) {
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
sp<device::V3_7::ICameraDevice> cameraDevice3_7;
- sp<device::V3_8::ICameraDevice> cameraDevice3_8;
- castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7, &cameraDevice3_8);
+ castDevice(device3_x, deviceVersion, &cameraDevice3_5, &cameraDevice3_7);
bool supported = false;
ret = cameraDevice3_5->isStreamCombinationSupported(config3_4,
@@ -8282,95 +7369,6 @@
return false;
}
-void CameraHidlTest::get10BitDynamicRangeProfiles(const camera_metadata_t* staticMeta,
- std::vector<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap> *profiles) {
- ASSERT_NE(nullptr, staticMeta);
- ASSERT_NE(nullptr, profiles);
- camera_metadata_ro_entry entry;
- std::unordered_set<int64_t> entries;
- int rc = find_camera_metadata_ro_entry(staticMeta,
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP, &entry);
- ASSERT_EQ(rc, 0);
- ASSERT_TRUE(entry.count > 0);
- ASSERT_EQ(entry.count % 3, 0);
-
- for (uint32_t i = 0; i < entry.count; i += 3) {
- ASSERT_NE(entry.data.i64[i],
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
- ASSERT_EQ(entries.find(entry.data.i64[i]), entries.end());
- entries.insert(entry.data.i64[i]);
- profiles->emplace_back(
- static_cast<CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap>
- (entry.data.i64[i]));
- }
-
- if (!entries.empty()) {
- ASSERT_NE(entries.find(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10),
- entries.end());
- }
-}
-
-bool CameraHidlTest::is10BitDynamicRangeCapable(const camera_metadata_t* staticMeta) {
- camera_metadata_ro_entry scalarEntry;
- int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
- &scalarEntry);
- if (rc == 0) {
- for (uint32_t i = 0; i < scalarEntry.count; i++) {
- if (scalarEntry.data.u8[i] ==
- ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) {
- return true;
- }
- }
- }
- return false;
-}
-
-void CameraHidlTest::verify10BitMetadata(HandleImporter& importer,
- const InFlightRequest& request,
- CameraMetadataEnumAndroidRequestAvailableDynamicRangeProfilesMap profile) {
- for (const auto& b : request.resultOutputBuffers) {
- bool smpte2086Present = importer.isSmpte2086Present(b.buffer.buffer.getNativeHandle());
- bool smpte2094_10Present = importer.isSmpte2094_10Present(
- b.buffer.buffer.getNativeHandle());
- bool smpte2094_40Present = importer.isSmpte2094_40Present(
- b.buffer.buffer.getNativeHandle());
-
- switch (static_cast<int64_t>(profile)) {
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10:
- ASSERT_FALSE(smpte2086Present);
- ASSERT_FALSE(smpte2094_10Present);
- ASSERT_FALSE(smpte2094_40Present);
- break;
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
- ASSERT_TRUE(smpte2086Present);
- ASSERT_FALSE(smpte2094_10Present);
- ASSERT_FALSE(smpte2094_40Present);
- break;
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
- ASSERT_FALSE(smpte2086Present);
- ASSERT_FALSE(smpte2094_10Present);
- ASSERT_TRUE(smpte2094_40Present);
- break;
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF:
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO:
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM:
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO:
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF:
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_REF_PO:
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM:
- case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_8B_HDR_OEM_PO:
- ASSERT_FALSE(smpte2086Present);
- ASSERT_TRUE(smpte2094_10Present);
- ASSERT_FALSE(smpte2094_40Present);
- break;
- default:
- ALOGE("%s: Unexpected 10-bit dynamic range profile: %" PRId64,
- __FUNCTION__, profile);
- ADD_FAILURE();
- }
- }
-}
-
bool CameraHidlTest::isDepthOnly(const camera_metadata_t* staticMeta) {
camera_metadata_ro_entry scalarEntry;
camera_metadata_ro_entry depthEntry;
@@ -8534,9 +7532,8 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
- castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
+ castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+ &session3_7);
*useHalBufManager = false;
status = find_camera_metadata_ro_entry(staticMeta,
@@ -8667,19 +7664,11 @@
void CameraHidlTest::castDevice(const sp<device::V3_2::ICameraDevice>& device,
int32_t deviceVersion,
sp<device::V3_5::ICameraDevice>* device3_5 /*out*/,
- sp<device::V3_7::ICameraDevice>* device3_7 /*out*/,
- sp<device::V3_8::ICameraDevice>* device3_8 /*out*/) {
+ sp<device::V3_7::ICameraDevice>* device3_7 /*out*/) {
ASSERT_NE(nullptr, device3_5);
ASSERT_NE(nullptr, device3_7);
- ASSERT_NE(nullptr, device3_8);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8: {
- auto castResult = device::V3_8::ICameraDevice::castFrom(device);
- ASSERT_TRUE(castResult.isOk());
- *device3_8 = castResult;
- }
- [[fallthrough]];
case CAMERA_DEVICE_API_VERSION_3_7: {
auto castResult = device::V3_7::ICameraDevice::castFrom(device);
ASSERT_TRUE(castResult.isOk());
@@ -8723,27 +7712,19 @@
}
//Cast camera device session to corresponding version
-void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
- sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
- sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
- sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
- sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/,
- sp<device::V3_7::ICameraDeviceSession> *session3_7 /*out*/,
- sp<device::V3_8::ICameraDeviceSession> *session3_8 /*out*/) {
+void CameraHidlTest::castSession(const sp<ICameraDeviceSession>& session, int32_t deviceVersion,
+ sp<device::V3_3::ICameraDeviceSession>* session3_3 /*out*/,
+ sp<device::V3_4::ICameraDeviceSession>* session3_4 /*out*/,
+ sp<device::V3_5::ICameraDeviceSession>* session3_5 /*out*/,
+ sp<device::V3_6::ICameraDeviceSession>* session3_6 /*out*/,
+ sp<device::V3_7::ICameraDeviceSession>* session3_7 /*out*/) {
ASSERT_NE(nullptr, session3_3);
ASSERT_NE(nullptr, session3_4);
ASSERT_NE(nullptr, session3_5);
ASSERT_NE(nullptr, session3_6);
ASSERT_NE(nullptr, session3_7);
- ASSERT_NE(nullptr, session3_8);
switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_3_8: {
- auto castResult = device::V3_8::ICameraDeviceSession::castFrom(session);
- ASSERT_TRUE(castResult.isOk());
- *session3_8 = castResult;
- }
- [[fallthrough]];
case CAMERA_DEVICE_API_VERSION_3_7: {
auto castResult = device::V3_7::ICameraDeviceSession::castFrom(session);
ASSERT_TRUE(castResult.isOk());
@@ -9661,9 +8642,8 @@
sp<device::V3_5::ICameraDeviceSession> session3_5;
sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_7::ICameraDeviceSession> session3_7;
- sp<device::V3_8::ICameraDeviceSession> session3_8;
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5,
- &session3_6, &session3_7, &session3_8);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6,
+ &session3_7);
ASSERT_NE(nullptr, session3_5.get());
hidl_vec<int32_t> streamIds(1);
@@ -9905,7 +8885,7 @@
size_t CONFIG_ENTRY_TYPE_OFFSET = 3;
size_t CONFIG_ENTRY_BITFIELD_OFFSET = 4;
uint32_t maxPublicUsecase =
- ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END_3_8;
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END;
uint32_t vendorUsecaseStart =
ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START;
uint32_t usecaseMask = (1 << vendorUsecaseStart) - 1;
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 462698c..fe03732 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -39,7 +39,7 @@
using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
using ::aidl::android::hardware::camera::metadata::SensorPixelMode;
using ::aidl::android::hardware::camera::provider::CameraIdAndStreamCombination;
-using ::aidl::android::hardware::camera::provider::ICameraProviderCallbackDefault;
+using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
using ::ndk::ScopedAStatus;
@@ -86,7 +86,7 @@
// Test if ICameraProvider::setCallback returns Status::OK
TEST_P(CameraAidlTest, setCallback) {
- struct ProviderCb : public ICameraProviderCallbackDefault {
+ struct ProviderCb : public BnCameraProviderCallback {
ScopedAStatus cameraDeviceStatusChange(const std::string& cameraDeviceName,
CameraDeviceStatus newStatus) override {
ALOGI("camera device status callback name %s, status %d", cameraDeviceName.c_str(),
@@ -109,11 +109,11 @@
}
};
- std::shared_ptr<ProviderCb> cb = ProviderCb::make<ProviderCb>();
+ std::shared_ptr<ProviderCb> cb = ndk::SharedRefBase::make<ProviderCb>();
ScopedAStatus ret = mProvider->setCallback(cb);
ASSERT_TRUE(ret.isOk());
ret = mProvider->setCallback(nullptr);
- ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), ret.getServiceSpecificError());
}
// Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
@@ -399,9 +399,6 @@
}
}
}
-
- ret = mProvider->setCallback(nullptr);
- ASSERT_TRUE(ret.isOk());
}
// Check dump functionality.
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index fd83e37..c11fc0c 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -55,26 +55,6 @@
using ::ndk::SpAIBinder;
namespace {
-bool matchDeviceName(const std::string& deviceName, const std::string& providerType,
- std::string* deviceVersion, std::string* cameraId) {
- // expected format: device@<major>.<minor>/<type>/<id>
- std::stringstream pattern;
- pattern << "device@[0-9]+\\.[0-9]+/" << providerType << "/(.+)";
- std::regex e(pattern.str());
-
- std::smatch sm;
- if (std::regex_match(deviceName, sm, e)) {
- if (deviceVersion != nullptr) {
- *deviceVersion = sm[1];
- }
- if (cameraId != nullptr) {
- *cameraId = sm[2];
- }
- return true;
- }
- return false;
-}
-
bool parseProviderName(const std::string& serviceDescriptor, std::string* type /*out*/,
uint32_t* id /*out*/) {
if (!type || !id) {
@@ -498,13 +478,11 @@
bool CameraAidlTest::matchDeviceName(const std::string& deviceName, const std::string& providerType,
std::string* deviceVersion, std::string* cameraId) {
- // "device@<version>/legacy/<id>"
- std::string pattern;
- pattern.append("device@([0-9]+\\.[0-9]+)/");
- pattern.append(providerType);
- pattern.append("/(.+)");
+ // expected format: device@<major>.<minor>/<type>/<id>
+ std::stringstream pattern;
+ pattern << "device@([0-9]+\\.[0-9]+)/" << providerType << "/(.+)";
+ std::regex e(pattern.str());
- std::regex e(pattern);
std::smatch sm;
if (std::regex_match(deviceName, sm, e)) {
if (deviceVersion != nullptr) {
@@ -1160,7 +1138,7 @@
}
std::string version, cameraId;
- ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId));
+ ASSERT_TRUE(matchDeviceName(cameraName, mProviderType, &version, &cameraId));
std::unordered_set<std::string> physicalIds;
rc = getPhysicalCameraIds(metadata, &physicalIds);
ASSERT_TRUE(isUltraHighResCamera || Status::OK == rc);
@@ -1192,7 +1170,7 @@
SystemCameraKind physSystemCameraKind = SystemCameraKind::PUBLIC;
for (auto& deviceName : deviceNames) {
std::string publicVersion, publicId;
- ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
+ ASSERT_TRUE(matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
if (physicalId == publicId) {
isPublicId = true;
fullPublicId = deviceName;
diff --git a/drm/aidl/vts/drm_hal_common.cpp b/drm/aidl/vts/drm_hal_common.cpp
index de7dc28..7de8167 100644
--- a/drm/aidl/vts/drm_hal_common.cpp
+++ b/drm/aidl/vts/drm_hal_common.cpp
@@ -73,6 +73,7 @@
}
const char* kDrmIface = "android.hardware.drm.IDrmFactory";
+const int MAX_OPEN_SESSION_ATTEMPTS = 3;
std::string HalFullName(const std::string& iface, const std::string& basename) {
return iface + '/' + basename;
@@ -328,9 +329,19 @@
*/
SessionId DrmHalTest::openSession() {
SessionId sessionId;
- auto ret = drmPlugin->openSession(SecurityLevel::DEFAULT, &sessionId);
- EXPECT_OK(ret);
- EXPECT_NE(0u, sessionId.size());
+
+ int attmpt = 0;
+ while (attmpt++ < MAX_OPEN_SESSION_ATTEMPTS) {
+ auto ret = drmPlugin->openSession(SecurityLevel::DEFAULT, &sessionId);
+ if(DrmErr(ret) == Status::ERROR_DRM_NOT_PROVISIONED) {
+ provision();
+ } else {
+ EXPECT_OK(ret);
+ EXPECT_NE(0u, sessionId.size());
+ break;
+ }
+ }
+
return sessionId;
}
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index 7855b51..cf2c90d 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -19,6 +19,7 @@
#include "Gnss.h"
#include <inttypes.h>
#include <log/log.h>
+#include <utils/Timers.h>
#include "AGnss.h"
#include "AGnssRil.h"
#include "DeviceFileReader.h"
@@ -28,7 +29,6 @@
#include "GnssConfiguration.h"
#include "GnssDebug.h"
#include "GnssGeofence.h"
-#include "GnssMeasurementInterface.h"
#include "GnssNavigationMessageInterface.h"
#include "GnssPsds.h"
#include "GnssVisibilityControl.h"
@@ -95,6 +95,9 @@
}
mIsActive = true;
+ mThreadBlocker.reset();
+ // notify measurement engine to update measurement interval
+ mGnssMeasurementInterface->setLocationEnabled(true);
this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
mThread = std::thread([this]() {
this->reportSvStatus();
@@ -102,8 +105,12 @@
std::this_thread::sleep_for(std::chrono::milliseconds(TTFF_MILLIS));
mFirstFixReceived = true;
}
- while (mIsActive == true) {
+ do {
+ if (!mIsActive) {
+ break;
+ }
this->reportSvStatus();
+ this->reportNmea();
auto currentLocation = getLocationFromHW();
mGnssPowerIndication->notePowerConsumption();
@@ -113,12 +120,29 @@
const auto location = Utils::getMockLocation();
this->reportLocation(location);
}
- std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
- }
+ } while (mIsActive && mThreadBlocker.wait_for(std::chrono::milliseconds(mMinIntervalMs)));
});
return ScopedAStatus::ok();
}
+ScopedAStatus Gnss::stop() {
+ ALOGD("stop");
+ mIsActive = false;
+ mGnssMeasurementInterface->setLocationEnabled(false);
+ this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_END);
+ mThreadBlocker.notify();
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::close() {
+ ALOGD("close");
+ sGnssCallback = nullptr;
+ return ScopedAStatus::ok();
+}
+
void Gnss::reportLocation(const GnssLocation& location) const {
std::unique_lock<std::mutex> lock(mMutex);
if (sGnssCallback == nullptr) {
@@ -153,7 +177,6 @@
std::vector<GnssSvInfo> Gnss::filterBlocklistedSatellites(
std::vector<GnssSvInfo> gnssSvInfoList) const {
- ALOGD("filterBlocklistedSatellites");
for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
if (mGnssConfiguration->isBlocklisted(gnssSvInfoList[i])) {
gnssSvInfoList[i].svFlag &= ~(uint32_t)IGnssCallback::GnssSvFlags::USED_IN_FIX;
@@ -174,14 +197,19 @@
}
}
-ScopedAStatus Gnss::stop() {
- ALOGD("stop");
- mIsActive = false;
- this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_END);
- if (mThread.joinable()) {
- mThread.join();
+void Gnss::reportNmea() const {
+ if (mIsNmeaActive) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (sGnssCallback == nullptr) {
+ ALOGE("%s: sGnssCallback is null.", __func__);
+ return;
+ }
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ auto status = sGnssCallback->gnssNmeaCb(now, "$TEST,0,1,2,3,4,5");
+ if (!status.isOk()) {
+ ALOGE("%s: Unable to invoke callback", __func__);
+ }
}
- return ScopedAStatus::ok();
}
ScopedAStatus Gnss::startSvStatus() {
@@ -197,16 +225,12 @@
}
ScopedAStatus Gnss::startNmea() {
ALOGD("startNmea");
+ mIsNmeaActive = true;
return ScopedAStatus::ok();
}
ScopedAStatus Gnss::stopNmea() {
ALOGD("stopNmea");
- return ScopedAStatus::ok();
-}
-
-ScopedAStatus Gnss::close() {
- ALOGD("close");
- sGnssCallback = nullptr;
+ mIsNmeaActive = false;
return ScopedAStatus::ok();
}
@@ -249,7 +273,8 @@
ScopedAStatus Gnss::setPositionMode(const PositionModeOptions& options) {
ALOGD("setPositionMode. minIntervalMs:%d, lowPowerMode:%d", options.minIntervalMs,
(int)options.lowPowerMode);
- mMinIntervalMs = options.minIntervalMs;
+ mMinIntervalMs = std::max(1000, options.minIntervalMs);
+ mGnssMeasurementInterface->setLocationInterval(mMinIntervalMs);
return ScopedAStatus::ok();
}
@@ -283,8 +308,10 @@
ScopedAStatus Gnss::getExtensionGnssMeasurement(
std::shared_ptr<IGnssMeasurementInterface>* iGnssMeasurement) {
ALOGD("getExtensionGnssMeasurement");
-
- *iGnssMeasurement = SharedRefBase::make<GnssMeasurementInterface>();
+ if (mGnssMeasurementInterface == nullptr) {
+ mGnssMeasurementInterface = SharedRefBase::make<GnssMeasurementInterface>();
+ }
+ *iGnssMeasurement = mGnssMeasurementInterface;
return ScopedAStatus::ok();
}
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
index 1489b4b..df10fc8 100644
--- a/gnss/aidl/default/Gnss.h
+++ b/gnss/aidl/default/Gnss.h
@@ -32,7 +32,9 @@
#include <mutex>
#include <thread>
#include "GnssConfiguration.h"
+#include "GnssMeasurementInterface.h"
#include "GnssPowerIndication.h"
+#include "Utils.h"
namespace aidl::android::hardware::gnss {
@@ -84,6 +86,7 @@
std::shared_ptr<GnssConfiguration> mGnssConfiguration;
std::shared_ptr<GnssPowerIndication> mGnssPowerIndication;
+ std::shared_ptr<GnssMeasurementInterface> mGnssMeasurementInterface;
private:
void reportLocation(const GnssLocation&) const;
@@ -93,14 +96,17 @@
std::vector<IGnssCallback::GnssSvInfo> gnssSvInfoList) const;
void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
std::unique_ptr<GnssLocation> getLocationFromHW();
+ void reportNmea() const;
static std::shared_ptr<IGnssCallback> sGnssCallback;
std::atomic<long> mMinIntervalMs;
std::atomic<bool> mIsActive;
std::atomic<bool> mIsSvStatusActive;
+ std::atomic<bool> mIsNmeaActive;
std::atomic<bool> mFirstFixReceived;
std::thread mThread;
+ ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
mutable std::mutex mMutex;
};
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index 2c7241b..606de07 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -33,10 +33,11 @@
std::shared_ptr<IGnssMeasurementCallback> GnssMeasurementInterface::sCallback = nullptr;
-GnssMeasurementInterface::GnssMeasurementInterface() : mMinIntervalMillis(1000) {}
+GnssMeasurementInterface::GnssMeasurementInterface()
+ : mIntervalMs(1000), mLocationIntervalMs(1000), mFutures(std::vector<std::future<void>>()) {}
GnssMeasurementInterface::~GnssMeasurementInterface() {
- stop();
+ waitForStoppingThreads();
}
ndk::ScopedAStatus GnssMeasurementInterface::setCallback(
@@ -44,8 +45,10 @@
const bool enableCorrVecOutputs) {
ALOGD("setCallback: enableFullTracking: %d enableCorrVecOutputs: %d", (int)enableFullTracking,
(int)enableCorrVecOutputs);
- std::unique_lock<std::mutex> lock(mMutex);
- sCallback = callback;
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = callback;
+ }
if (mIsActive) {
ALOGW("GnssMeasurement callback already set. Resetting the callback...");
@@ -60,14 +63,16 @@
const std::shared_ptr<IGnssMeasurementCallback>& callback, const Options& options) {
ALOGD("setCallbackWithOptions: fullTracking:%d, corrVec:%d, intervalMs:%d",
(int)options.enableFullTracking, (int)options.enableCorrVecOutputs, options.intervalMs);
- std::unique_lock<std::mutex> lock(mMutex);
- sCallback = callback;
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = callback;
+ }
if (mIsActive) {
ALOGW("GnssMeasurement callback already set. Resetting the callback...");
stop();
}
- mMinIntervalMillis = options.intervalMs;
+ mIntervalMs = std::max(options.intervalMs, 1000);
start(options.enableCorrVecOutputs);
return ndk::ScopedAStatus::ok();
@@ -75,18 +80,35 @@
ndk::ScopedAStatus GnssMeasurementInterface::close() {
ALOGD("close");
- stop();
- std::unique_lock<std::mutex> lock(mMutex);
- sCallback = nullptr;
- mMinIntervalMillis = 1000;
+ if (mIsActive) {
+ stop();
+ }
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = nullptr;
+ }
+ mIntervalMs = 1000;
return ndk::ScopedAStatus::ok();
}
void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) {
ALOGD("start");
+
+ if (mIsActive) {
+ ALOGD("restarting since measurement has started");
+ stop();
+ }
+ // Wait for stopping previous thread.
+ waitForStoppingThreads();
+
mIsActive = true;
+ mThreadBlocker.reset();
mThread = std::thread([this, enableCorrVecOutputs]() {
- while (mIsActive == true) {
+ int intervalMs;
+ do {
+ if (!mIsActive) {
+ break;
+ }
std::string rawMeasurementStr = "";
if (ReplayUtils::hasGnssDeviceFile() &&
ReplayUtils::isGnssRawMeasurement(
@@ -103,15 +125,19 @@
auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs);
this->reportMeasurement(measurement);
}
- std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
- }
+ intervalMs =
+ (mLocationEnabled) ? std::min(mLocationIntervalMs, mIntervalMs) : mIntervalMs;
+ } while (mIsActive && mThreadBlocker.wait_for(std::chrono::milliseconds(intervalMs)));
});
- mThread.detach();
}
void GnssMeasurementInterface::stop() {
ALOGD("stop");
mIsActive = false;
+ mThreadBlocker.notify();
+ if (mThread.joinable()) {
+ mFutures.push_back(std::async(std::launch::async, [this] { mThread.join(); }));
+ }
}
void GnssMeasurementInterface::reportMeasurement(const GnssData& data) {
@@ -128,4 +154,21 @@
callbackCopy->gnssMeasurementCb(data);
}
+void GnssMeasurementInterface::setLocationInterval(const int intervalMs) {
+ mLocationIntervalMs = intervalMs;
+}
+
+void GnssMeasurementInterface::setLocationEnabled(const bool enabled) {
+ mLocationEnabled = enabled;
+}
+
+void GnssMeasurementInterface::waitForStoppingThreads() {
+ for (auto& future : mFutures) {
+ ALOGD("Stopping previous thread.");
+ future.wait();
+ ALOGD("Done stopping thread.");
+ }
+ mFutures.clear();
+}
+
} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssMeasurementInterface.h b/gnss/aidl/default/GnssMeasurementInterface.h
index bf77806..bb08027 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.h
+++ b/gnss/aidl/default/GnssMeasurementInterface.h
@@ -19,8 +19,10 @@
#include <aidl/android/hardware/gnss/BnGnssMeasurementCallback.h>
#include <aidl/android/hardware/gnss/BnGnssMeasurementInterface.h>
#include <atomic>
+#include <future>
#include <mutex>
#include <thread>
+#include "Utils.h"
namespace aidl::android::hardware::gnss {
@@ -35,15 +37,22 @@
ndk::ScopedAStatus setCallbackWithOptions(
const std::shared_ptr<IGnssMeasurementCallback>& callback,
const Options& options) override;
+ void setLocationInterval(const int intervalMs);
+ void setLocationEnabled(const bool enabled);
private:
void start(const bool enableCorrVecOutputs);
void stop();
void reportMeasurement(const GnssData&);
+ void waitForStoppingThreads();
- std::atomic<long> mMinIntervalMillis;
+ std::atomic<long> mIntervalMs;
+ std::atomic<long> mLocationIntervalMs;
std::atomic<bool> mIsActive;
+ std::atomic<bool> mLocationEnabled;
std::thread mThread;
+ std::vector<std::future<void>> mFutures;
+ ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
// Guarded by mMutex
static std::shared_ptr<IGnssMeasurementCallback> sCallback;
diff --git a/gnss/aidl/default/GnssNavigationMessageInterface.cpp b/gnss/aidl/default/GnssNavigationMessageInterface.cpp
index 4bc859d..75b9624 100644
--- a/gnss/aidl/default/GnssNavigationMessageInterface.cpp
+++ b/gnss/aidl/default/GnssNavigationMessageInterface.cpp
@@ -32,7 +32,7 @@
GnssNavigationMessageInterface::GnssNavigationMessageInterface() : mMinIntervalMillis(1000) {}
GnssNavigationMessageInterface::~GnssNavigationMessageInterface() {
- stop();
+ waitForStoppingThreads();
}
ndk::ScopedAStatus GnssNavigationMessageInterface::setCallback(
@@ -46,7 +46,9 @@
ndk::ScopedAStatus GnssNavigationMessageInterface::close() {
ALOGD("close");
- stop();
+ if (mIsActive) {
+ stop();
+ }
std::unique_lock<std::mutex> lock(mMutex);
sCallback = nullptr;
return ndk::ScopedAStatus::ok();
@@ -54,9 +56,20 @@
void GnssNavigationMessageInterface::start() {
ALOGD("start");
+
+ if (mIsActive) {
+ ALOGD("restarting since nav msg has started");
+ stop();
+ }
+ // Wait for stopping previous thread.
+ waitForStoppingThreads();
+
mIsActive = true;
mThread = std::thread([this]() {
- while (mIsActive == true) {
+ do {
+ if (!mIsActive) {
+ break;
+ }
GnssNavigationMessage message = {
.svid = 19,
.type = GnssNavigationMessageType::GPS_L1CA,
@@ -66,15 +79,18 @@
.data = std::vector<uint8_t>(40, 0xF9),
};
this->reportMessage(message);
- std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
- }
+ } while (mIsActive &&
+ mThreadBlocker.wait_for(std::chrono::milliseconds(mMinIntervalMillis)));
});
- mThread.detach();
}
void GnssNavigationMessageInterface::stop() {
ALOGD("stop");
mIsActive = false;
+ mThreadBlocker.notify();
+ if (mThread.joinable()) {
+ mFutures.push_back(std::async(std::launch::async, [this] { mThread.join(); }));
+ }
}
void GnssNavigationMessageInterface::reportMessage(const GnssNavigationMessage& message) {
@@ -91,4 +107,13 @@
callbackCopy->gnssNavigationMessageCb(message);
}
+void GnssNavigationMessageInterface::waitForStoppingThreads() {
+ for (auto& future : mFutures) {
+ ALOGD("Stopping previous thread.");
+ future.wait();
+ ALOGD("Done stopping thread.");
+ }
+ mFutures.clear();
+}
+
} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssNavigationMessageInterface.h b/gnss/aidl/default/GnssNavigationMessageInterface.h
index 600b23a..b335348 100644
--- a/gnss/aidl/default/GnssNavigationMessageInterface.h
+++ b/gnss/aidl/default/GnssNavigationMessageInterface.h
@@ -18,7 +18,9 @@
#include <aidl/android/hardware/gnss/BnGnssNavigationMessageInterface.h>
#include <atomic>
+#include <future>
#include <thread>
+#include "Utils.h"
namespace aidl::android::hardware::gnss {
@@ -34,10 +36,13 @@
void start();
void stop();
void reportMessage(const IGnssNavigationMessageCallback::GnssNavigationMessage& message);
+ void waitForStoppingThreads();
std::atomic<long> mMinIntervalMillis;
std::atomic<bool> mIsActive;
std::thread mThread;
+ std::vector<std::future<void>> mFutures;
+ ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
// Guarded by mMutex
static std::shared_ptr<IGnssNavigationMessageCallback> sCallback;
diff --git a/gnss/aidl/vts/GnssCallbackAidl.cpp b/gnss/aidl/vts/GnssCallbackAidl.cpp
index 77a2506..2f6128b 100644
--- a/gnss/aidl/vts/GnssCallbackAidl.cpp
+++ b/gnss/aidl/vts/GnssCallbackAidl.cpp
@@ -31,7 +31,7 @@
}
Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue /* status */) {
- ALOGI("gnssSvStatusCb");
+ ALOGI("gnssStatusCb");
return Status::ok();
}
@@ -47,7 +47,8 @@
return Status::ok();
}
-Status GnssCallbackAidl::gnssNmeaCb(const int64_t /* timestamp */, const std::string& /* nmea */) {
+Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
+ nmea_cbq_.store(std::make_pair(timestamp, nmea));
return Status::ok();
}
diff --git a/gnss/aidl/vts/GnssCallbackAidl.h b/gnss/aidl/vts/GnssCallbackAidl.h
index 209728d..a9495ba 100644
--- a/gnss/aidl/vts/GnssCallbackAidl.h
+++ b/gnss/aidl/vts/GnssCallbackAidl.h
@@ -17,6 +17,7 @@
#pragma once
#include <android/hardware/gnss/BnGnssCallback.h>
+#include <utility>
#include "GnssCallbackEventQueue.h"
/* Callback class for data & Event. */
@@ -26,7 +27,8 @@
: capabilities_cbq_("capabilities"),
info_cbq_("system_info"),
location_cbq_("location"),
- sv_info_list_cbq_("sv_info"){};
+ sv_info_list_cbq_("sv_info"),
+ nmea_cbq_("nmea"){};
~GnssCallbackAidl(){};
android::binder::Status gnssSetCapabilitiesCb(const int capabilities) override;
@@ -55,4 +57,6 @@
android::hardware::gnss::common::GnssCallbackEventQueue<
std::vector<android::hardware::gnss::IGnssCallback::GnssSvInfo>>
sv_info_list_cbq_;
+ android::hardware::gnss::common::GnssCallbackEventQueue<std::pair<int64_t, std::string>>
+ nmea_cbq_;
};
\ No newline at end of file
diff --git a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
index c4fad7f..a553954 100644
--- a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
+++ b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
@@ -24,12 +24,10 @@
android::binder::Status GnssMeasurementCallbackAidl::gnssMeasurementCb(const GnssData& gnssData) {
ALOGI("gnssMeasurementCb");
- ALOGI("elapsedRealtime: flags = %d, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
+ ALOGV("elapsedRealtime: flags = 0x%X, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
gnssData.elapsedRealtime.flags, gnssData.elapsedRealtime.timestampNs,
gnssData.elapsedRealtime.timeUncertaintyNs);
- for (const auto& measurement : gnssData.measurements) {
- ALOGI("measurement.receivedSvTimeInNs=%" PRId64, measurement.receivedSvTimeInNs);
- }
+
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 f184f81..407ac0c 100644
--- a/gnss/aidl/vts/gnss_hal_test.cpp
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -18,15 +18,50 @@
#include "gnss_hal_test.h"
#include <hidl/ServiceManagement.h>
+#include <algorithm>
+#include <cmath>
#include "Utils.h"
+using android::hardware::gnss::GnssClock;
using android::hardware::gnss::GnssConstellationType;
+using android::hardware::gnss::GnssData;
using android::hardware::gnss::GnssLocation;
+using android::hardware::gnss::GnssMeasurement;
using android::hardware::gnss::IGnss;
using android::hardware::gnss::IGnssCallback;
+using android::hardware::gnss::IGnssMeasurementInterface;
using android::hardware::gnss::common::Utils;
using GnssConstellationTypeV2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
+namespace {
+// The difference between the mean of the received intervals and the requested interval should not
+// be larger mInterval * ALLOWED_MEAN_ERROR_RATIO
+constexpr double ALLOWED_MEAN_ERROR_RATIO = 0.25;
+
+// The standard deviation computed for the deltas should not be bigger
+// than mInterval * ALLOWED_STDEV_ERROR_RATIO or MIN_STDEV_MS, whichever is higher.
+constexpr double ALLOWED_STDEV_ERROR_RATIO = 0.50;
+constexpr double MIN_STDEV_MS = 1000;
+
+double computeMean(std::vector<int>& deltas) {
+ long accumulator = 0;
+ for (auto& d : deltas) {
+ accumulator += d;
+ }
+ return accumulator / deltas.size();
+}
+
+double computeStdev(double mean, std::vector<int>& deltas) {
+ double accumulator = 0;
+ for (auto& d : deltas) {
+ double diff = d - mean;
+ accumulator += diff * diff;
+ }
+ return std::sqrt(accumulator / (deltas.size() - 1));
+}
+
+} // anonymous namespace
+
void GnssHalTest::SetUp() {
// Get AIDL handle
aidl_gnss_hal_ = android::waitForDeclaredService<IGnssAidl>(String16(GetParam().c_str()));
@@ -97,20 +132,26 @@
ASSERT_TRUE(status.isOk());
}
-bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec,
- const bool low_power_mode) {
+bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode,
+ const bool start_sv_status, const bool start_nmea) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
// Invoke the super method.
return GnssHalTestTemplate<IGnss_V2_1>::StartAndCheckFirstLocation(min_interval_msec,
low_power_mode);
}
-
SetPositionMode(min_interval_msec, low_power_mode);
+
auto status = aidl_gnss_hal_->start();
EXPECT_TRUE(status.isOk());
- status = aidl_gnss_hal_->startSvStatus();
- EXPECT_TRUE(status.isOk());
+ if (start_sv_status) {
+ status = aidl_gnss_hal_->startSvStatus();
+ EXPECT_TRUE(status.isOk());
+ }
+ if (start_nmea) {
+ status = aidl_gnss_hal_->startNmea();
+ EXPECT_TRUE(status.isOk());
+ }
/*
* GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
@@ -131,6 +172,12 @@
return false;
}
+bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec,
+ const bool low_power_mode) {
+ return StartAndCheckFirstLocation(min_interval_msec, low_power_mode,
+ /* start_sv_status= */ true, /* start_nmea= */ true);
+}
+
void GnssHalTest::StopAndClearLocations() {
ALOGD("StopAndClearLocations");
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
@@ -139,6 +186,8 @@
}
auto status = aidl_gnss_hal_->stopSvStatus();
EXPECT_TRUE(status.isOk());
+ status = aidl_gnss_hal_->stopNmea();
+ EXPECT_TRUE(status.isOk());
status = aidl_gnss_hal_->stop();
EXPECT_TRUE(status.isOk());
@@ -153,7 +202,8 @@
aidl_gnss_cb_->location_cbq_.reset();
}
-void GnssHalTest::StartAndCheckLocations(int count) {
+void GnssHalTest::StartAndCheckLocations(const int count, const bool start_sv_status,
+ const bool start_nmea) {
if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
// Invoke the super method.
return GnssHalTestTemplate<IGnss_V2_1>::StartAndCheckLocations(count);
@@ -162,7 +212,8 @@
const int kLocationTimeoutSubsequentSec = 2;
const bool kLowPowerMode = false;
- EXPECT_TRUE(StartAndCheckFirstLocation(kMinIntervalMsec, kLowPowerMode));
+ EXPECT_TRUE(StartAndCheckFirstLocation(kMinIntervalMsec, kLowPowerMode, start_sv_status,
+ start_nmea));
for (int i = 1; i < count; i++) {
EXPECT_TRUE(aidl_gnss_cb_->location_cbq_.retrieve(aidl_gnss_cb_->last_location_,
@@ -177,6 +228,10 @@
}
}
+void GnssHalTest::StartAndCheckLocations(const int count) {
+ StartAndCheckLocations(count, /* start_sv_status= */ true, /* start_nmea= */ true);
+}
+
std::list<std::vector<IGnssCallback::GnssSvInfo>> GnssHalTest::convertToAidl(
const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>>& sv_info_list) {
std::list<std::vector<IGnssCallback::GnssSvInfo>> aidl_sv_info_list;
@@ -313,3 +368,109 @@
return constellation_to_blocklist;
}
+
+void GnssHalTest::checkGnssMeasurementClockFields(const GnssData& measurement) {
+ Utils::checkElapsedRealtime(measurement.elapsedRealtime);
+ ASSERT_TRUE(measurement.clock.gnssClockFlags >= 0 &&
+ measurement.clock.gnssClockFlags <=
+ (GnssClock::HAS_LEAP_SECOND | GnssClock::HAS_TIME_UNCERTAINTY |
+ GnssClock::HAS_FULL_BIAS | GnssClock::HAS_BIAS |
+ GnssClock::HAS_BIAS_UNCERTAINTY | GnssClock::HAS_DRIFT |
+ GnssClock::HAS_DRIFT_UNCERTAINTY));
+}
+
+void GnssHalTest::checkGnssMeasurementFlags(const GnssMeasurement& measurement) {
+ ASSERT_TRUE(measurement.flags >= 0 &&
+ measurement.flags <=
+ (GnssMeasurement::HAS_SNR | GnssMeasurement::HAS_CARRIER_FREQUENCY |
+ GnssMeasurement::HAS_CARRIER_CYCLES | GnssMeasurement::HAS_CARRIER_PHASE |
+ GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY |
+ GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL |
+ GnssMeasurement::HAS_FULL_ISB | GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY |
+ GnssMeasurement::HAS_SATELLITE_ISB |
+ GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY |
+ GnssMeasurement::HAS_SATELLITE_PVT |
+ GnssMeasurement::HAS_CORRELATION_VECTOR));
+}
+
+void GnssHalTest::checkGnssMeasurementFields(const GnssMeasurement& measurement,
+ const GnssData& data) {
+ checkGnssMeasurementFlags(measurement);
+ // Verify CodeType is valid.
+ ASSERT_NE(measurement.signalType.codeType, "");
+ // Verify basebandCn0DbHz is valid.
+ ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
+
+ if (((measurement.flags & GnssMeasurement::HAS_FULL_ISB) > 0) &&
+ ((measurement.flags & GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
+ ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB) > 0) &&
+ ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY) > 0)) {
+ GnssConstellationType referenceConstellation =
+ data.clock.referenceSignalTypeForIsb.constellation;
+ double carrierFrequencyHz = data.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
+ std::string codeType = data.clock.referenceSignalTypeForIsb.codeType;
+
+ ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
+ referenceConstellation <= GnssConstellationType::IRNSS);
+ ASSERT_TRUE(carrierFrequencyHz > 0);
+ ASSERT_NE(codeType, "");
+
+ ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
+ ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
+ ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
+ ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
+ }
+}
+
+void GnssHalTest::startMeasurementWithInterval(
+ int intervalMs, const sp<IGnssMeasurementInterface>& iGnssMeasurement,
+ sp<GnssMeasurementCallbackAidl>& callback) {
+ ALOGD("Start requesting measurement at interval of %d millis.", intervalMs);
+ IGnssMeasurementInterface::Options options;
+ options.intervalMs = intervalMs;
+ auto status = iGnssMeasurement->setCallbackWithOptions(callback, options);
+ ASSERT_TRUE(status.isOk());
+}
+
+void GnssHalTest::collectMeasurementIntervals(const sp<GnssMeasurementCallbackAidl>& callback,
+ const int numMeasurementEvents,
+ const int timeoutSeconds,
+ std::vector<int>& deltasMs) {
+ int64_t lastElapsedRealtimeMillis = 0;
+ 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);
+ for (const auto& measurement : lastGnssData.measurements) {
+ checkGnssMeasurementFields(measurement, lastGnssData);
+ }
+
+ long currentElapsedRealtimeMillis = lastGnssData.elapsedRealtime.timestampNs * 1e-6;
+ if (lastElapsedRealtimeMillis != 0) {
+ deltasMs.push_back(currentElapsedRealtimeMillis - lastElapsedRealtimeMillis);
+ }
+ lastElapsedRealtimeMillis = currentElapsedRealtimeMillis;
+ }
+}
+
+void GnssHalTest::assertMeanAndStdev(int intervalMs, std::vector<int>& deltasMs) {
+ double mean = computeMean(deltasMs);
+ double stdev = computeStdev(mean, deltasMs);
+ EXPECT_TRUE(std::abs(mean - intervalMs) <= intervalMs * ALLOWED_MEAN_ERROR_RATIO)
+ << "Test failed, because the mean of intervals is " << mean
+ << " millis. The test requires that abs(" << mean << " - " << intervalMs
+ << ") <= " << intervalMs * ALLOWED_MEAN_ERROR_RATIO
+ << " millis, when the requested interval is " << intervalMs << " millis.";
+
+ double maxStdev = std::max(MIN_STDEV_MS, intervalMs * ALLOWED_STDEV_ERROR_RATIO);
+ EXPECT_TRUE(stdev <= maxStdev)
+ << "Test failed, because the stdev of intervals is " << stdev
+ << " millis, which must be <= " << maxStdev
+ << " millis, when the requested interval is " << intervalMs << " millis.";
+ ALOGD("Mean of interval deltas in millis: %.1lf", mean);
+ ALOGD("Stdev of interval deltas in millis: %.1lf", stdev);
+}
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
index d479af3..645fc82 100644
--- a/gnss/aidl/vts/gnss_hal_test.h
+++ b/gnss/aidl/vts/gnss_hal_test.h
@@ -25,6 +25,7 @@
#include <android/hardware/gnss/2.1/IGnss.h>
#include "GnssBatchingCallback.h"
#include "GnssCallbackAidl.h"
+#include "GnssMeasurementCallbackAidl.h"
#include "v2_1/gnss_hal_test_template.h"
using IGnss_V2_1 = android::hardware::gnss::V2_1::IGnss;
@@ -68,8 +69,11 @@
const bool check_speed);
void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
bool StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode);
+ bool StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode,
+ const bool start_sv_status, const bool start_nmea);
void StopAndClearLocations();
- void StartAndCheckLocations(int count);
+ void StartAndCheckLocations(const int count);
+ void StartAndCheckLocations(const int count, const bool start_sv_status, const bool start_nmea);
android::hardware::gnss::GnssConstellationType startLocationAndGetNonGpsConstellation(
const int locations_to_await, const int gnss_sv_info_list_timeout);
@@ -85,6 +89,19 @@
sv_info_list,
const int min_observations);
+ void checkGnssMeasurementClockFields(const android::hardware::gnss::GnssData& measurement);
+ void checkGnssMeasurementFlags(const android::hardware::gnss::GnssMeasurement& measurement);
+ void checkGnssMeasurementFields(const android::hardware::gnss::GnssMeasurement& measurement,
+ const android::hardware::gnss::GnssData& data);
+ void startMeasurementWithInterval(
+ int intervalMillis,
+ const sp<android::hardware::gnss::IGnssMeasurementInterface>& iMeasurement,
+ sp<GnssMeasurementCallbackAidl>& callback);
+ void collectMeasurementIntervals(const sp<GnssMeasurementCallbackAidl>& callback,
+ const int numMeasurementEvents, const int timeoutSeconds,
+ std::vector<int>& deltaMs);
+ void assertMeanAndStdev(int intervalMillis, std::vector<int>& deltasMillis);
+
sp<IGnssAidl> aidl_gnss_hal_;
sp<GnssCallbackAidl> aidl_gnss_cb_; // Primary callback interface
};
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 54946fb..f926c40 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -28,7 +28,9 @@
#include <android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.h>
#include <android/hardware/gnss/visibility_control/IGnssVisibilityControl.h>
#include <cutils/properties.h>
+#include <utils/SystemClock.h>
#include <cmath>
+#include <utility>
#include "AGnssCallbackAidl.h"
#include "AGnssRilCallbackAidl.h"
#include "GnssAntennaInfoCallbackAidl.h"
@@ -376,58 +378,6 @@
}
}
-void CheckGnssMeasurementClockFields(const GnssData& measurement) {
- Utils::checkElapsedRealtime(measurement.elapsedRealtime);
- ASSERT_TRUE(measurement.clock.gnssClockFlags >= 0 &&
- measurement.clock.gnssClockFlags <=
- (GnssClock::HAS_LEAP_SECOND | GnssClock::HAS_TIME_UNCERTAINTY |
- GnssClock::HAS_FULL_BIAS | GnssClock::HAS_BIAS |
- GnssClock::HAS_BIAS_UNCERTAINTY | GnssClock::HAS_DRIFT |
- GnssClock::HAS_DRIFT_UNCERTAINTY));
-}
-
-void CheckGnssMeasurementFlags(const GnssMeasurement& measurement) {
- ASSERT_TRUE(measurement.flags >= 0 &&
- measurement.flags <=
- (GnssMeasurement::HAS_SNR | GnssMeasurement::HAS_CARRIER_FREQUENCY |
- GnssMeasurement::HAS_CARRIER_CYCLES | GnssMeasurement::HAS_CARRIER_PHASE |
- GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY |
- GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL |
- GnssMeasurement::HAS_FULL_ISB | GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY |
- GnssMeasurement::HAS_SATELLITE_ISB |
- GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY |
- GnssMeasurement::HAS_SATELLITE_PVT |
- GnssMeasurement::HAS_CORRELATION_VECTOR));
-}
-
-void CheckGnssMeasurementFields(const GnssMeasurement& measurement, const GnssData& data) {
- CheckGnssMeasurementFlags(measurement);
- // Verify CodeType is valid.
- ASSERT_NE(measurement.signalType.codeType, "");
- // Verify basebandCn0DbHz is valid.
- ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
-
- if (((measurement.flags & GnssMeasurement::HAS_FULL_ISB) > 0) &&
- ((measurement.flags & GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
- ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB) > 0) &&
- ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY) > 0)) {
- GnssConstellationType referenceConstellation =
- data.clock.referenceSignalTypeForIsb.constellation;
- double carrierFrequencyHz = data.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
- std::string codeType = data.clock.referenceSignalTypeForIsb.codeType;
-
- ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
- referenceConstellation <= GnssConstellationType::IRNSS);
- ASSERT_TRUE(carrierFrequencyHz > 0);
- ASSERT_NE(codeType, "");
-
- ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
- ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
- ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
- ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
- }
-}
-
/*
* TestGnssMeasurementExtensionAndSatellitePvt:
* 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
@@ -465,10 +415,10 @@
ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
// Validity check GnssData fields
- CheckGnssMeasurementClockFields(lastMeasurement);
+ checkGnssMeasurementClockFields(lastMeasurement);
for (const auto& measurement : lastMeasurement.measurements) {
- CheckGnssMeasurementFields(measurement, lastMeasurement);
+ checkGnssMeasurementFields(measurement, lastMeasurement);
if (measurement.flags & GnssMeasurement::HAS_SATELLITE_PVT &&
kIsSatellitePvtSupported == true) {
ALOGD("Found a measurement with SatellitePvt");
@@ -525,10 +475,10 @@
ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
// Validity check GnssData fields
- CheckGnssMeasurementClockFields(lastMeasurement);
+ checkGnssMeasurementClockFields(lastMeasurement);
for (const auto& measurement : lastMeasurement.measurements) {
- CheckGnssMeasurementFields(measurement, lastMeasurement);
+ checkGnssMeasurementFields(measurement, lastMeasurement);
if (measurement.flags & GnssMeasurement::HAS_CORRELATION_VECTOR) {
correlationVectorFound = true;
ASSERT_TRUE(measurement.correlationVectors.size() > 0);
@@ -1242,48 +1192,6 @@
}
/*
- * TestGnssMeasurementSetCallbackWithOptions:
- * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
- * 2. Sets a GnssMeasurementCallback with intervalMillis option, waits for measurements reported,
- * and verifies mandatory fields are valid.
- */
-TEST_P(GnssHalTest, TestGnssMeasurementSetCallbackWithOptions) {
- if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
- return;
- }
- const int kFirstGnssMeasurementTimeoutSeconds = 10;
- const int kNumMeasurementEvents = 5;
-
- sp<IGnssMeasurementInterface> iGnssMeasurement;
- auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
- ASSERT_TRUE(status.isOk());
- ASSERT_TRUE(iGnssMeasurement != nullptr);
-
- auto callback = sp<GnssMeasurementCallbackAidl>::make();
- IGnssMeasurementInterface::Options options;
- options.intervalMs = 2000;
- status = iGnssMeasurement->setCallbackWithOptions(callback, options);
- ASSERT_TRUE(status.isOk());
-
- for (int i = 0; i < kNumMeasurementEvents; i++) {
- GnssData lastMeasurement;
- ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
- kFirstGnssMeasurementTimeoutSeconds));
- EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
- ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
-
- // Validity check GnssData fields
- CheckGnssMeasurementClockFields(lastMeasurement);
- for (const auto& measurement : lastMeasurement.measurements) {
- CheckGnssMeasurementFields(measurement, lastMeasurement);
- }
- }
-
- status = iGnssMeasurement->close();
- ASSERT_TRUE(status.isOk());
-}
-
-/*
* TestGnssAgcInGnssMeasurement:
* 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
* 2. Sets a GnssMeasurementCallback, waits for a measurement.
@@ -1293,7 +1201,7 @@
return;
}
const int kFirstGnssMeasurementTimeoutSeconds = 10;
- const int kNumMeasurementEvents = 15;
+ const int kNumMeasurementEvents = 5;
sp<IGnssMeasurementInterface> iGnssMeasurement;
auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
@@ -1313,7 +1221,7 @@
ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
// Validity check GnssData fields
- CheckGnssMeasurementClockFields(lastMeasurement);
+ checkGnssMeasurementClockFields(lastMeasurement);
ASSERT_TRUE(lastMeasurement.gnssAgcs.size() > 0);
for (const auto& gnssAgc : lastMeasurement.gnssAgcs) {
@@ -1444,3 +1352,143 @@
Utils::getMockMeasurementCorrections_aidl());
ASSERT_TRUE(status.isOk());
}
+
+/*
+ * TestStopSvStatusAndNmea:
+ * 1. Call stopSvStatus and stopNmea.
+ * 2. Start location and verify that
+ * - no SvStatus is received.
+ * - no Nmea is received.
+ */
+TEST_P(GnssHalTest, TestStopSvStatusAndNmea) {
+ if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+ return;
+ }
+ auto status = aidl_gnss_hal_->stopSvStatus();
+ EXPECT_TRUE(status.isOk());
+ status = aidl_gnss_hal_->stopNmea();
+ EXPECT_TRUE(status.isOk());
+
+ int kLocationsToAwait = 5;
+ aidl_gnss_cb_->location_cbq_.reset();
+ aidl_gnss_cb_->sv_info_list_cbq_.reset();
+ aidl_gnss_cb_->nmea_cbq_.reset();
+ StartAndCheckLocations(/* count= */ kLocationsToAwait,
+ /* start_sv_status= */ false, /* start_nmea= */ false);
+ int location_called_count = aidl_gnss_cb_->location_cbq_.calledCount();
+ ALOGD("Observed %d GnssSvStatus, and %d Nmea while awaiting %d locations (%d received)",
+ aidl_gnss_cb_->sv_info_list_cbq_.size(), aidl_gnss_cb_->nmea_cbq_.size(),
+ kLocationsToAwait, location_called_count);
+
+ // Ensure that no SvStatus & no Nmea is received.
+ EXPECT_EQ(aidl_gnss_cb_->sv_info_list_cbq_.size(), 0);
+ EXPECT_EQ(aidl_gnss_cb_->nmea_cbq_.size(), 0);
+
+ StopAndClearLocations();
+}
+
+/*
+ * TestGnssMeasurementIntervals_WithoutLocation:
+ * 1. start measurement with interval
+ * 2. verify that the received measurement intervals have expected mean and stdev
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIntervals_WithoutLocation) {
+ if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+ return;
+ }
+
+ std::vector<int> intervals({2000, 4000});
+ std::vector<int> numEvents({10, 5});
+
+ sp<IGnssMeasurementInterface> iGnssMeasurement;
+ auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+ ALOGD("TestGnssMeasurementIntervals_WithoutLocation");
+ for (int i = 0; i < intervals.size(); i++) {
+ auto callback = sp<GnssMeasurementCallbackAidl>::make();
+ startMeasurementWithInterval(intervals[i], iGnssMeasurement, callback);
+
+ std::vector<int> deltas;
+ collectMeasurementIntervals(callback, numEvents[i], /* timeoutSeconds= */ 10, deltas);
+
+ status = iGnssMeasurement->close();
+ ASSERT_TRUE(status.isOk());
+
+ assertMeanAndStdev(intervals[i], deltas);
+ }
+}
+
+/*
+ * TestGnssMeasurementIntervals_LocationOnBeforeMeasurement:
+ * 1. start measurement with interval
+ * 2. verify that the received measurement intervals have expected mean and stdev
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIntervals_LocationOnBeforeMeasurement) {
+ if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+ return;
+ }
+
+ std::vector<int> intervals({2000});
+
+ sp<IGnssMeasurementInterface> iGnssMeasurement;
+ auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+ int locationIntervalMs = 1000;
+
+ // Start location first and then start measurement
+ ALOGD("TestGnssMeasurementIntervals_LocationOnBeforeMeasurement");
+ StartAndCheckFirstLocation(locationIntervalMs, /* lowPowerMode= */ false);
+ for (auto& intervalMs : intervals) {
+ auto callback = sp<GnssMeasurementCallbackAidl>::make();
+ startMeasurementWithInterval(intervalMs, iGnssMeasurement, callback);
+
+ std::vector<int> deltas;
+ collectMeasurementIntervals(callback, /*numEvents=*/10, /*timeoutSeconds=*/10, deltas);
+
+ status = iGnssMeasurement->close();
+ ASSERT_TRUE(status.isOk());
+
+ assertMeanAndStdev(locationIntervalMs, deltas);
+ }
+ StopAndClearLocations();
+}
+
+/*
+ * TestGnssMeasurementIntervals:
+ * 1. start measurement with interval
+ * 2. verify that the received measurement intervals have expected mean and stdev
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIntervals_LocationOnAfterMeasurement) {
+ if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+ return;
+ }
+
+ std::vector<int> intervals({2000});
+
+ sp<IGnssMeasurementInterface> iGnssMeasurement;
+ auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+ int locationIntervalMs = 1000;
+ // Start location first and then start measurement
+ ALOGD("TestGnssMeasurementIntervals_LocationOnAfterMeasurement");
+ for (auto& intervalMs : intervals) {
+ auto callback = sp<GnssMeasurementCallbackAidl>::make();
+ startMeasurementWithInterval(intervalMs, iGnssMeasurement, callback);
+
+ StartAndCheckFirstLocation(locationIntervalMs, /* lowPowerMode= */ false);
+ std::vector<int> deltas;
+ collectMeasurementIntervals(callback, /*numEvents=*/10, /*timeoutSeconds=*/10, deltas);
+
+ StopAndClearLocations();
+ status = iGnssMeasurement->close();
+ ASSERT_TRUE(status.isOk());
+
+ assertMeanAndStdev(locationIntervalMs, deltas);
+ }
+}
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index 7065a6fb..ad8f539 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -56,6 +56,31 @@
static hidl_vec<V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo> getMockAntennaInfos();
};
+struct ThreadBlocker {
+ // returns false if unblocked:
+ template <class R, class P>
+ bool wait_for(std::chrono::duration<R, P> const& time) {
+ std::unique_lock<std::mutex> lock(m);
+ return !cv.wait_for(lock, time, [&] { return terminate; });
+ }
+
+ void notify() {
+ std::unique_lock<std::mutex> lock(m);
+ terminate = true;
+ cv.notify_all();
+ }
+
+ void reset() {
+ std::unique_lock<std::mutex> lock(m);
+ terminate = false;
+ }
+
+ private:
+ std::condition_variable cv;
+ std::mutex m;
+ bool terminate = false;
+};
+
} // namespace common
} // namespace gnss
} // namespace hardware
diff --git a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
index c9d058d..59af5cf 100644
--- a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
+++ b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
@@ -153,7 +153,6 @@
if (error == EX_SERVICE_SPECIFIC) {
error = status.getServiceSpecificError();
EXPECT_NE(OK, error) << "Failed to set error properly";
- EXPECT_EQ(OK, error) << "Failed to allocate";
} else {
EXPECT_EQ(OK, error) << "Allocation transport failure";
}
@@ -278,6 +277,7 @@
if (!supported) {
ASSERT_EQ(nullptr, buffer.get())
<< "Allocation succeeded, but IMapper::isSupported was false";
+ GTEST_SKIP();
} else {
ASSERT_NE(nullptr, buffer.get()) << "Allocation failed, but IMapper::isSupported was true";
}
@@ -319,6 +319,7 @@
if (!supported) {
ASSERT_EQ(nullptr, buffer.get())
<< "Allocation succeeded, but IMapper::isSupported was false";
+ GTEST_SKIP();
} else {
ASSERT_NE(nullptr, buffer.get()) << "Allocation failed, but IMapper::isSupported was true";
}
@@ -375,4 +376,4 @@
[](auto info) -> std::string {
std::string name = std::to_string(info.index) + "/" + std::get<2>(info.param).name;
return Sanitize(name);
- });
\ No newline at end of file
+ });
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index 8732d53..c0a0c07 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -32,6 +32,7 @@
"TestCommandReader.cpp",
],
static_libs: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
@@ -39,6 +40,7 @@
"libgtest",
],
export_static_lib_headers: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index 55aaf12..e777010 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -318,7 +318,7 @@
[this] {
ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
/*errOnFailure=*/false));
- if (mGralloc4->getAllocator() == nullptr || mGralloc4->getMapper() == nullptr) {
+ if (!mGralloc4->hasAllocator() || mGralloc4->getMapper() == nullptr) {
mGralloc4 = nullptr;
ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
/*errOnFailure=*/false));
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 9ffd7d5..502036e 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -32,14 +32,17 @@
// TODO(b/64437680): Assume these libs are always available on the device.
shared_libs: [
"libbase",
+ "libbinder_ndk",
"libfmq",
"libsync",
+ "android.hardware.common-V2-ndk",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@4.0",
],
static_libs: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
@@ -49,10 +52,14 @@
"android.hardware.graphics.mapper@2.1-vts",
"android.hardware.graphics.mapper@3.0-vts",
"android.hardware.graphics.mapper@4.0-vts",
+ "libaidlcommonsupport",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
],
disable_framework: true,
- test_suites: ["general-tests", "vts"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
}
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index aa8e541..cca5323 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -35,6 +35,7 @@
"libui",
],
static_libs: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer3-V1-ndk",
@@ -52,6 +53,7 @@
"android.hardware.graphics.mapper@4.0-vts",
],
export_static_lib_headers: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.mapper@2.1-vts",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index a526137..7de4007 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -184,7 +184,7 @@
ALOGD("Attempting to initialize gralloc4");
ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
/*errOnFailure=*/false));
- if (mGralloc4->getMapper() == nullptr || mGralloc4->getAllocator() == nullptr) {
+ if (mGralloc4->getMapper() == nullptr || !mGralloc4->hasAllocator()) {
mGralloc4 = nullptr;
ALOGD("Failed to initialize gralloc4, initializing gralloc3");
ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index dd519e7..960b62d 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -45,18 +45,21 @@
"libGLESv1_CM",
"libGLESv2",
"libbase",
+ "libbinder_ndk",
"libfmq",
"libgui",
"libhidlbase",
"libprocessgroup",
"libsync",
"libui",
+ "android.hardware.common-V2-ndk",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@4.0",
],
static_libs: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
@@ -70,6 +73,7 @@
"android.hardware.graphics.mapper@2.1-vts",
"android.hardware.graphics.mapper@3.0-vts",
"android.hardware.graphics.mapper@4.0-vts",
+ "libaidlcommonsupport",
"libgtest",
"librenderengine",
"libshaders",
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index 70384ac..40b77d5 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -32,15 +32,18 @@
// TODO(b/64437680): Assume these libs are always available on the device.
shared_libs: [
"libbase",
+ "libbinder_ndk",
"libfmq",
"libhidlbase",
"libsync",
+ "android.hardware.common-V2-ndk",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@4.0",
],
static_libs: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
@@ -54,6 +57,7 @@
"android.hardware.graphics.mapper@2.1-vts",
"android.hardware.graphics.mapper@3.0-vts",
"android.hardware.graphics.mapper@4.0-vts",
+ "libaidlcommonsupport",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
@@ -61,5 +65,8 @@
"android.hardware.graphics.composer@2.3-command-buffer",
],
disable_framework: true,
- test_suites: ["general-tests", "vts"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
}
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
index 5ef861c..de31975 100644
--- a/graphics/composer/2.4/utils/vts/Android.bp
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -32,6 +32,7 @@
"TestCommandReader.cpp",
],
static_libs: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3-vts",
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
index 22ae7c4..b73ea94 100644
--- a/graphics/composer/2.4/vts/functional/Android.bp
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -32,14 +32,17 @@
// TODO(b/64437680): Assume these libs are always available on the device.
shared_libs: [
"libbase",
+ "libbinder_ndk",
"libfmq",
"libsync",
+ "android.hardware.common-V2-ndk",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@4.0",
],
static_libs: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
@@ -55,6 +58,7 @@
"android.hardware.graphics.mapper@2.1-vts",
"android.hardware.graphics.mapper@3.0-vts",
"android.hardware.graphics.mapper@4.0-vts",
+ "libaidlcommonsupport",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
@@ -63,5 +67,8 @@
"android.hardware.graphics.composer@2.4-command-buffer",
],
disable_framework: true,
- test_suites: ["general-tests", "vts"],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
}
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
index 6331498..7abf5db 100644
--- a/graphics/mapper/4.0/utils/vts/Android.bp
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -32,14 +32,21 @@
"-g",
],
static_libs: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@4.0",
+ "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
+ "libaidlcommonsupport",
],
shared_libs: [
+ "libbinder_ndk",
"libgralloctypes",
+ "libvndksupport",
],
export_static_lib_headers: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@4.0",
+ "android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0",
],
export_include_dirs: ["include"],
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 4a6f68d..e4a2535 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+#include <aidlcommonsupport/NativeHandle.h>
#include <android-base/properties.h>
+#include <android/binder_manager.h>
#include <gralloctypes/Gralloc4.h>
#include <mapper-vts/4.0/MapperVts.h>
@@ -35,8 +37,14 @@
}
void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
- mAllocator = IAllocator::getService(allocatorServiceName);
- ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+ mAidlAllocator = aidl::android::hardware::graphics::allocator::IAllocator::fromBinder(
+ ndk::SpAIBinder(AServiceManager_checkService(allocatorServiceName.c_str())));
+
+ if (mAidlAllocator == nullptr) {
+ mHidlAllocator = IAllocator::getService(allocatorServiceName);
+ }
+ ASSERT_TRUE(nullptr != mAidlAllocator || mHidlAllocator != nullptr)
+ << "failed to get allocator service";
mMapper = IMapper::getService(mapperServiceName);
ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
@@ -45,7 +53,12 @@
void Gralloc::initNoErr(const std::string& allocatorServiceName,
const std::string& mapperServiceName) {
- mAllocator = IAllocator::getService(allocatorServiceName);
+ mAidlAllocator = aidl::android::hardware::graphics::allocator::IAllocator::fromBinder(
+ ndk::SpAIBinder(AServiceManager_checkService(allocatorServiceName.c_str())));
+
+ if (mAidlAllocator == nullptr) {
+ mHidlAllocator = IAllocator::getService(allocatorServiceName);
+ }
mMapper = IMapper::getService(mapperServiceName);
if (mMapper.get()) {
@@ -68,10 +81,6 @@
mImportedBuffers.clear();
}
-sp<IAllocator> Gralloc::getAllocator() const {
- return mAllocator;
-}
-
const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle,
enum Tolerance /*tolerance*/) {
const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
@@ -90,40 +99,40 @@
uint32_t* outStride) {
std::vector<const native_handle_t*> bufferHandles;
bufferHandles.reserve(count);
- mAllocator->allocate(descriptor, count,
- [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
- if (canTolerate(tolerance, tmpError)) {
- return;
- }
- if (tmpError != Error::NONE) {
- if (base::GetIntProperty("ro.vendor.build.version.sdk", 0, 0,
- INT_MAX) < 33) {
- GTEST_SKIP() << "Old vendor grallocs may not support P010";
- } else {
- GTEST_FAIL() << "failed to allocate buffers";
- }
- }
- ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
+ auto callback = [&](Error error, uint32_t stride,
+ const hidl_vec<hidl_handle>& buffers) -> void {
+ if (canTolerate(tolerance, error)) {
+ return;
+ }
- for (uint32_t i = 0; i < count; i++) {
- const native_handle_t* bufferHandle = nullptr;
- if (import) {
- ASSERT_NO_FATAL_FAILURE(
- bufferHandle = importBuffer(tmpBuffers[i], tolerance));
- } else {
- ASSERT_NO_FATAL_FAILURE(
- bufferHandle = cloneBuffer(tmpBuffers[i], tolerance));
- }
- if (bufferHandle) {
- bufferHandles.push_back(bufferHandle);
- }
- }
+ if (error != Error::NONE) {
+ if (base::GetIntProperty("ro.vendor.build.version.sdk", 0, 0, INT_MAX) < 33) {
+ GTEST_SKIP() << "Old vendor grallocs may not support P010";
+ } else {
+ GTEST_FAIL() << "failed to allocate buffers";
+ }
+ }
+ ASSERT_EQ(count, buffers.size()) << "invalid buffer array";
- if (outStride) {
- *outStride = tmpStride;
- }
- });
+ for (uint32_t i = 0; i < count; i++) {
+ const native_handle_t* bufferHandle = nullptr;
+ if (import) {
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = importBuffer(buffers[i], tolerance));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = cloneBuffer(buffers[i], tolerance));
+ }
+ if (bufferHandle) {
+ bufferHandles.push_back(bufferHandle);
+ }
+ }
+
+ if (outStride) {
+ *outStride = stride;
+ }
+ };
+
+ rawAllocate(descriptor, count, callback);
if (::testing::Test::HasFatalFailure()) {
bufferHandles.clear();
@@ -147,6 +156,23 @@
return buffers[0];
}
+void Gralloc::rawAllocate(
+ const BufferDescriptor& descriptor, uint32_t count,
+ std::function<void(Error, uint32_t, const hidl_vec<hidl_handle>&)> callback) {
+ if (mAidlAllocator) {
+ aidl::android::hardware::graphics::allocator::AllocationResult result;
+ auto status = mAidlAllocator->allocate(descriptor, count, &result);
+ const Error error = toHidlError(status);
+ std::vector<hidl_handle> handles;
+ for (const auto& aidlHandle : result.buffers) {
+ handles.push_back(hidl_handle(makeFromAidl(aidlHandle)));
+ }
+ callback(error, result.stride, handles);
+ } else {
+ mHidlAllocator->allocate(descriptor, count, callback);
+ }
+}
+
sp<IMapper> Gralloc::getMapper() const {
return mMapper;
}
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index c5406c9..b956e49 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -20,6 +20,8 @@
#include <unordered_set>
#include <vector>
+#include <aidl/android/hardware/graphics/allocator/AllocationError.h>
+#include <aidl/android/hardware/graphics/allocator/IAllocator.h>
#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
#include <android/hardware/graphics/mapper/4.0/IMapper.h>
#include <gtest/gtest.h>
@@ -51,9 +53,33 @@
const std::string& mapperServiceName = "default", bool errOnFailure = true);
~Gralloc();
+ static Error toHidlError(aidl::android::hardware::graphics::allocator::AllocationError error) {
+ switch (error) {
+ case aidl::android::hardware::graphics::allocator::AllocationError::BAD_DESCRIPTOR:
+ return Error::BAD_DESCRIPTOR;
+ case aidl::android::hardware::graphics::allocator::AllocationError::NO_RESOURCES:
+ return Error::NO_RESOURCES;
+ case aidl::android::hardware::graphics::allocator::AllocationError::UNSUPPORTED:
+ return Error::UNSUPPORTED;
+ }
+ }
+ static Error toHidlError(const ndk::ScopedAStatus& status) {
+ if (status.isOk()) {
+ return Error::NONE;
+ }
+
+ if (status.getExceptionCode() != EX_SERVICE_SPECIFIC) {
+ return Error::NO_RESOURCES;
+ }
+
+ return toHidlError(
+ static_cast<aidl::android::hardware::graphics::allocator::AllocationError>(
+ status.getServiceSpecificError()));
+ }
+
// IAllocator methods
- sp<IAllocator> getAllocator() const;
+ bool hasAllocator() { return mHidlAllocator != nullptr || mAidlAllocator != nullptr; }
// When import is false, this simply calls IAllocator::allocate. When import
// is true, the returned buffers are also imported into the mapper.
@@ -81,6 +107,10 @@
return allocate(descriptorInfo, import, Tolerance::kToleranceStrict, outStride);
}
+ // Dispatches directly to the allocator
+ void rawAllocate(const BufferDescriptor& descriptor, uint32_t count,
+ std::function<void(Error, uint32_t, const hidl_vec<hidl_handle>&)> callback);
+
// IMapper methods
sp<IMapper> getMapper() const;
@@ -143,7 +173,8 @@
return cloneBuffer(rawHandle, Tolerance::kToleranceStrict);
}
- sp<IAllocator> mAllocator;
+ sp<IAllocator> mHidlAllocator;
+ std::shared_ptr<aidl::android::hardware::graphics::allocator::IAllocator> mAidlAllocator;
sp<IMapper> mMapper;
// Keep track of all cloned and imported handles. When a test fails with
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index 65bc380..e830633 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -25,20 +25,27 @@
cc_test {
name: "VtsHalGraphicsMapperV4_0TargetTest",
- defaults: ["VtsHalTargetTestDefaults"],
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
static_libs: [
"android.hardware.graphics.common-V3-ndk",
"android.hardware.graphics.mapper@4.0-vts",
+ "libaidlcommonsupport",
"libgralloctypes",
"libsync",
],
shared_libs: [
+ "android.hardware.graphics.allocator-V1-ndk",
"android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@4.0",
+ "libbinder_ndk",
+ "libvndksupport",
],
header_libs: [
"libsystem_headers",
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 2aac337..5a450e3 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -21,8 +21,12 @@
#include <thread>
#include <vector>
+#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/common/PixelFormat.h>
#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
+#include <aidlcommonsupport/NativeHandle.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
@@ -72,7 +76,7 @@
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
std::get<1>(GetParam())));
- ASSERT_NE(nullptr, mGralloc->getAllocator().get());
+ ASSERT_TRUE(mGralloc->hasAllocator());
ASSERT_NE(nullptr, mGralloc->getMapper().get());
mDummyDescriptorInfo.name = "dummy";
@@ -504,10 +508,10 @@
TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
// this assumes any valid descriptor is non-empty
BufferDescriptor descriptor;
- mGralloc->getAllocator()->allocate(descriptor, 1,
- [&](const auto& tmpError, const auto&, const auto&) {
- EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
- });
+
+ mGralloc->rawAllocate(descriptor, 1, [&](const auto& tmpError, const auto&, const auto&) {
+ EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
+ });
}
/**
@@ -535,9 +539,9 @@
std::atomic<uint64_t> allocationCount(0);
auto threadLoop = [&]() {
while (!timeUp) {
- mGralloc->getAllocator()->allocate(
- descriptor, 1,
- [&](const auto&, const auto&, const auto&) { allocationCount++; });
+ mGralloc->rawAllocate(descriptor, 1, [&](const auto&, const auto&, const auto&) {
+ allocationCount++;
+ });
}
};
@@ -2755,8 +2759,9 @@
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(info));
- Error err;
- mGralloc->getAllocator()->allocate(
+ Error err = Error::NONE;
+
+ mGralloc->rawAllocate(
descriptor, 1, [&](const auto& tmpError, const auto&, const auto& tmpBuffers) {
err = tmpError;
if (err == Error::NONE) {
@@ -2827,11 +2832,27 @@
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperHidlTest);
+
+namespace {
+std::vector<std::string> getAllocatorInstances() {
+ std::vector<std::string> instances;
+ for (auto halInstance : android::hardware::getAllHalInstanceNames(IAllocator::descriptor)) {
+ instances.emplace_back(std::move(halInstance));
+ }
+
+ for (auto aidlInstance : getAidlHalInstanceNames(
+ aidl::android::hardware::graphics::allocator::IAllocator::descriptor)) {
+ instances.emplace_back(std::move(aidlInstance));
+ }
+
+ return instances;
+}
+} // namespace
+
INSTANTIATE_TEST_CASE_P(
PerInstance, GraphicsMapperHidlTest,
testing::Combine(
- testing::ValuesIn(
- android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+ testing::ValuesIn(getAllocatorInstances()),
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index fee58a4..51ab110 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -59,16 +59,3 @@
],
require_root: true,
}
-
-java_test_host {
- name: "IdentityCredentialImplementedTest",
- libs: [
- "tradefed",
- "vts-core-tradefed-harness",
- ],
- srcs: ["src/**/*.java"],
- test_suites: [
- "vts",
- ],
- test_config: "IdentityCredentialImplementedTest.xml",
-}
diff --git a/identity/aidl/vts/AndroidTest.xml b/identity/aidl/vts/AndroidTest.xml
new file mode 100644
index 0000000..67132b0
--- /dev/null
+++ b/identity/aidl/vts/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs VtsHalIdentityTargetTest.">
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push"
+ value="VtsHalIdentityTargetTest->/data/local/tmp/VtsHalIdentityTargetTest" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="VtsHalIdentityTargetTest" />
+ <option name="native-test-timeout" value="300000"/>
+ </test>
+</configuration>
diff --git a/identity/aidl/vts/IdentityCredentialImplementedTest.xml b/identity/aidl/vts/IdentityCredentialImplementedTest.xml
deleted file mode 100644
index 1d76a74..0000000
--- a/identity/aidl/vts/IdentityCredentialImplementedTest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Runs IdentityCredentialImplementedTest">
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
-
- <test class="com.android.tradefed.testtype.HostTest" >
- <option name="jar" value="IdentityCredentialImplementedTest.jar" />
- </test>
-</configuration>
diff --git a/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java b/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
deleted file mode 100644
index 19568af..0000000
--- a/identity/aidl/vts/src/com/android/tests/security/identity/IdentityCredentialImplementedTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.tests.security.identity;
-
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeTrue;
-
-import android.platform.test.annotations.RequiresDevice;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(DeviceJUnit4ClassRunner.class)
-public class IdentityCredentialImplementedTest extends BaseHostJUnit4Test {
- // Returns the ro.vendor.api_level or 0 if not set.
- //
- // Throws NumberFormatException if ill-formatted.
- //
- // Throws DeviceNotAvailableException if device is not available.
- //
- private int getVendorApiLevel() throws NumberFormatException, DeviceNotAvailableException {
- String vendorApiLevelString =
- getDevice().executeShellCommand("getprop ro.vendor.api_level").trim();
- if (vendorApiLevelString.isEmpty()) {
- return 0;
- }
- return Integer.parseInt(vendorApiLevelString);
- }
-
- // As of Android 13 (API level 32), Identity Credential is required at feature version 202201
- // or newer.
- //
- @RequiresDevice
- @Test
- public void testIdentityCredentialIsImplemented() throws Exception {
- int vendorApiLevel = getVendorApiLevel();
- assumeTrue(vendorApiLevel >= 32);
-
- final String minimumFeatureVersionNeeded = "202201";
-
- String result = getDevice().executeShellCommand(
- "pm has-feature android.hardware.identity_credential "
- + minimumFeatureVersionNeeded);
- if (!result.trim().equals("true")) {
- fail("Identity Credential feature version " + minimumFeatureVersionNeeded
- + " required but not found");
- }
- }
-}
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 3d783d9..fe38e61 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -1262,7 +1262,7 @@
FILE* pFile = fopen(filename.c_str(), "a");
uint32_t appendLength = getRandomInt(1, 256);
for (uint32_t i = 0; i < appendLength; i++) {
- ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+ ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
}
fclose(pFile);
*skip = false;
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index a2013ec..f2cfa3f 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -1253,7 +1253,7 @@
FILE* pFile = fopen(filename.c_str(), "a");
uint32_t appendLength = getRandomInt(1, 256);
for (uint32_t i = 0; i < appendLength; i++) {
- ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+ ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
}
fclose(pFile);
*skip = false;
diff --git a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
index 7451f7e..da0fe64 100644
--- a/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/CompilationCachingTests.cpp
@@ -1068,7 +1068,7 @@
FILE* pFile = fopen(filename.c_str(), "a");
uint32_t appendLength = getRandomInt(1, 256);
for (uint32_t i = 0; i < appendLength; i++) {
- ASSERT_NE(fputc(getRandomInt<uint8_t>(0, 255), pFile), EOF);
+ ASSERT_NE(fputc(getRandomInt<uint16_t>(0, 255), pFile), EOF);
}
fclose(pFile);
*skip = false;
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index e0ca87f..2cfa04a 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -211,19 +211,6 @@
}
}
-// GAME_LOADING mode is required for all devices which ship on Android T
-// or later
-TEST_P(PowerAidl, hasGameLoading) {
- auto apiLevel = GetUintProperty<uint64_t>("ro.vendor.api_level", 0);
- ASSERT_NE(apiLevel, 0);
-
- if (apiLevel >= 33) {
- bool supported;
- ASSERT_TRUE(power->isModeSupported(Mode::GAME_LOADING, &supported).isOk());
- ASSERT_TRUE(supported);
- }
-}
-
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PowerAidl);
INSTANTIATE_TEST_SUITE_P(Power, PowerAidl,
testing::ValuesIn(::android::getAidlHalInstanceNames(IPower::descriptor)),
diff --git a/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl b/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl
index ee62d95..b256c9a 100644
--- a/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl
+++ b/radio/aidl/android/hardware/radio/messaging/GsmSmsMessage.aidl
@@ -27,6 +27,7 @@
/**
* SMS in PDU format as an ASCII hex string less the SMSC address.
* TP-Layer-Length is be "strlen(pdu)/2
+ * TP - MessageRef field of pdu must not be modified by modem
*/
String pdu;
}
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
index 666d617..2292c54 100644
--- a/radio/aidl/vts/radio_network_response.cpp
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -109,8 +109,9 @@
}
ndk::ScopedAStatus RadioNetworkResponse::getSystemSelectionChannelsResponse(
- const RadioResponseInfo& info, const std::vector<RadioAccessSpecifier>& /*specifier*/) {
+ const RadioResponseInfo& info, const std::vector<RadioAccessSpecifier>& specifiers) {
rspInfo = info;
+ this->specifiers = specifiers;
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 0bae374..c83571e 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -769,6 +769,16 @@
*/
TEST_P(RadioNetworkTest, setSystemSelectionChannels) {
serial = GetRandomSerialNumber();
+ ndk::ScopedAStatus res = radio_network->getSystemSelectionChannels(serial);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+ if (radioRsp_network->specifiers.size() == 0) {
+ // TODO (b/189255895): Throw an error once getSystemSelectionChannels is functional.
+ ALOGI("Skipped the test due to empty system selection channels.");
+ GTEST_SKIP();
+ }
+ std::vector<RadioAccessSpecifier> originalSpecifiers = radioRsp_network->specifiers;
RadioAccessSpecifierBands bandP900 =
RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
@@ -781,8 +791,8 @@
RadioAccessSpecifier specifier850 = {
.accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
- ndk::ScopedAStatus res =
- radio_network->setSystemSelectionChannels(serial, true, {specifierP900, specifier850});
+ serial = GetRandomSerialNumber();
+ res = radio_network->setSystemSelectionChannels(serial, true, {specifierP900, specifier850});
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -795,8 +805,8 @@
if (radioRsp_network->rspInfo.error == RadioError::NONE) {
serial = GetRandomSerialNumber();
- ndk::ScopedAStatus res = radio_network->setSystemSelectionChannels(
- serial, false, {specifierP900, specifier850});
+ res = radio_network->setSystemSelectionChannels(serial, false,
+ {specifierP900, specifier850});
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -805,6 +815,12 @@
toString(radioRsp_network->rspInfo.error).c_str());
EXPECT_EQ(RadioError::NONE, radioRsp_network->rspInfo.error);
}
+
+ serial = GetRandomSerialNumber();
+ res = radio_network->setSystemSelectionChannels(serial, true, originalSpecifiers);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
}
/*
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
index 29ba2f2..29f20e8 100644
--- a/radio/aidl/vts/radio_network_utils.h
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -45,6 +45,7 @@
CellIdentity barringCellIdentity;
std::vector<BarringInfo> barringInfoList;
UsageSetting usageSetting;
+ std::vector<RadioAccessSpecifier> specifiers;
virtual ndk::ScopedAStatus acknowledgeRequest(int32_t serial) override;
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 43dc84c..b9694e9 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -873,7 +873,7 @@
* The returned data is an encoded COSE_Mac0 structure, denoted MacedRootOfTrust in the
* following CDDL schema. Note that K_mac is the shared HMAC key used for auth tokens, etc.:
*
- * MacedRootOfTrust = [ ; COSE_Mac0 (untagged)
+ * MacedRootOfTrust = #6.17 [ ; COSE_Mac0 (tagged)
* protected: bstr .cbor {
* 1 : 5, ; Algorithm : HMAC-256
* },
@@ -891,7 +891,7 @@
* payload : bstr .cbor RootOfTrust,
* ]
*
- * RootOfTrust = [
+ * RootOfTrust = #6.40001 [ ; Tag 40001 indicates RoT v1.
* verifiedBootKey : bstr .size 32,
* deviceLocked : bool,
* verifiedBootState : &VerifiedBootState,
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index be21994..70b89c3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -31,7 +31,6 @@
#include <remote_prov/remote_prov_utils.h>
#include <keymaster/cppcose/cppcose.h>
-#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/keymint_utils.h>
#include <keymint_support/openssl_utils.h>
@@ -1497,6 +1496,60 @@
verify_subject(cert.get(), subject, self_signed);
}
+void verify_root_of_trust(const vector<uint8_t>& verified_boot_key, bool device_locked,
+ VerifiedBoot verified_boot_state,
+ const vector<uint8_t>& verified_boot_hash) {
+ char property_value[PROPERTY_VALUE_MAX] = {};
+
+ if (avb_verification_enabled()) {
+ EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
+ string prop_string(property_value);
+ EXPECT_EQ(prop_string.size(), 64);
+ EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
+
+ EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
+ if (!strcmp(property_value, "unlocked")) {
+ EXPECT_FALSE(device_locked);
+ } else {
+ EXPECT_TRUE(device_locked);
+ }
+
+ // Check that the device is locked if not debuggable, e.g., user build
+ // images in CTS. For VTS, debuggable images are used to allow adb root
+ // and the device is unlocked.
+ if (!property_get_bool("ro.debuggable", false)) {
+ EXPECT_TRUE(device_locked);
+ } else {
+ EXPECT_FALSE(device_locked);
+ }
+ }
+
+ // Verified boot key should be all 0's if the boot state is not verified or self signed
+ std::string empty_boot_key(32, '\0');
+ std::string verified_boot_key_str((const char*)verified_boot_key.data(),
+ verified_boot_key.size());
+ EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
+ if (!strcmp(property_value, "green")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "yellow")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "orange")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+ EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "red")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
+ } else {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+ EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ }
+}
+
bool verify_attestation_record(int32_t aidl_version, //
const string& challenge, //
const string& app_id, //
@@ -1551,8 +1604,6 @@
EXPECT_EQ(security_level, att_keymint_security_level);
EXPECT_EQ(security_level, att_attestation_security_level);
-
- char property_value[PROPERTY_VALUE_MAX] = {};
// TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
// keymint implementation will report YYYYMM dates instead of YYYYMMDD
// for the BOOT_PATCH_LEVEL.
@@ -1612,54 +1663,7 @@
error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
&verified_boot_state, &device_locked, &verified_boot_hash);
EXPECT_EQ(ErrorCode::OK, error);
-
- if (avb_verification_enabled()) {
- EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
- string prop_string(property_value);
- EXPECT_EQ(prop_string.size(), 64);
- EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
-
- EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
- if (!strcmp(property_value, "unlocked")) {
- EXPECT_FALSE(device_locked);
- } else {
- EXPECT_TRUE(device_locked);
- }
-
- // Check that the device is locked if not debuggable, e.g., user build
- // images in CTS. For VTS, debuggable images are used to allow adb root
- // and the device is unlocked.
- if (!property_get_bool("ro.debuggable", false)) {
- EXPECT_TRUE(device_locked);
- } else {
- EXPECT_FALSE(device_locked);
- }
- }
-
- // Verified boot key should be all 0's if the boot state is not verified or self signed
- std::string empty_boot_key(32, '\0');
- std::string verified_boot_key_str((const char*)verified_boot_key.data(),
- verified_boot_key.size());
- EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
- if (!strcmp(property_value, "green")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
- EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "yellow")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
- EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "orange")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
- EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "red")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
- } else {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
- EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- }
+ verify_root_of_trust(verified_boot_key, device_locked, verified_boot_state, verified_boot_hash);
att_sw_enforced.Sort();
expected_sw_enforced.Sort();
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 2634ab7..043d8b5 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -31,6 +31,7 @@
#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
#include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
+#include <keymint_support/attestation_record.h>
#include <keymint_support/authorization_set.h>
#include <keymint_support/openssl_utils.h>
@@ -363,7 +364,10 @@
void verify_subject_and_serial(const Certificate& certificate, //
const uint64_t expected_serial, //
const string& subject, bool self_signed);
-
+void verify_root_of_trust(const vector<uint8_t>& verified_boot_key, //
+ bool device_locked, //
+ VerifiedBoot verified_boot_state, //
+ const vector<uint8_t>& verified_boot_hash);
bool verify_attestation_record(int aidl_version, //
const string& challenge, //
const string& app_id, //
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 57704d5..38f5b1c 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -6186,7 +6186,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
string ciphertext;
AuthorizationSet finish_out_params;
ASSERT_EQ(ErrorCode::OK, UpdateAad(aad));
@@ -6229,7 +6229,7 @@
.Authorization(TAG_MAC_LENGTH, tag_bits);
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
// No data, AAD only.
EXPECT_EQ(ErrorCode::OK, UpdateAad("foo"));
@@ -6245,7 +6245,7 @@
begin_params.push_back(begin_out_params);
// Decrypt
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foofoo"));
string plaintext;
EXPECT_EQ(ErrorCode::OK, Finish(ciphertext, &plaintext));
@@ -6272,7 +6272,7 @@
.Authorization(TAG_MAC_LENGTH, 128);
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foo"));
string ciphertext;
@@ -6306,7 +6306,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
string ciphertext;
EXPECT_EQ(ErrorCode::OK, Finish(message, &ciphertext));
@@ -6315,7 +6315,7 @@
begin_params.push_back(begin_out_params);
// Decrypt.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("barfoo"));
string plaintext;
EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6342,7 +6342,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
string ciphertext;
AuthorizationSet finish_out_params;
@@ -6352,7 +6352,7 @@
begin_params.push_back(TAG_NONCE, AidlBuf("123456789012"));
// Decrypt.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad("foobar"));
string plaintext;
EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6384,7 +6384,7 @@
// Encrypt
AuthorizationSet begin_out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params, &begin_out_params));
EXPECT_EQ(ErrorCode::OK, UpdateAad(aad));
string ciphertext;
EXPECT_EQ(ErrorCode::OK, Finish(message, &ciphertext));
@@ -6396,7 +6396,7 @@
params.push_back(begin_out_params);
// Decrypt.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
EXPECT_EQ(ErrorCode::OK, UpdateAad(aad));
string plaintext;
EXPECT_EQ(ErrorCode::VERIFICATION_FAILED, Finish(ciphertext, &plaintext));
@@ -6509,7 +6509,7 @@
for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
++ciphertext[ciphertext.size() / 2];
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
string plaintext;
EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
ErrorCode error = Finish(&plaintext);
@@ -6781,7 +6781,7 @@
auto begin_params =
AuthorizationSetBuilder().BlockMode(blockMode).Padding(PaddingMode::NONE);
AuthorizationSet output_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
string ciphertext;
EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, "", &ciphertext));
@@ -6860,7 +6860,7 @@
for (size_t i = 0; i < kMaxPaddingCorruptionRetries; ++i) {
SCOPED_TRACE(testing::Message() << "i = " << i);
++ciphertext[ciphertext.size() / 2];
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
string plaintext;
EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext));
ErrorCode error = Finish(&plaintext);
@@ -6892,7 +6892,7 @@
AuthorizationSet input_params =
AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
AuthorizationSet output_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
string ciphertext;
for (size_t i = 0; i < message.size(); i += increment)
@@ -6906,7 +6906,7 @@
input_params.push_back(TAG_PADDING, PaddingMode::NONE);
output_params.Clear();
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
string plaintext;
for (size_t i = 0; i < ciphertext.size(); i += increment)
EXPECT_EQ(ErrorCode::OK, Update(ciphertext.substr(i, increment), &plaintext));
@@ -7023,7 +7023,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
}
}
@@ -7070,7 +7070,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, params));
}
}
@@ -7116,7 +7116,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
}
}
@@ -7163,7 +7163,7 @@
} else {
// Usage count limit tag is enforced by keystore, keymint does nothing.
EXPECT_TRUE(keystore_auths.Contains(TAG_USAGE_COUNT_LIMIT, 3U));
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::SIGN, params));
}
}
@@ -7476,7 +7476,7 @@
EXPECT_EQ(ErrorCode::OK, Abort(op_handles[j]))
<< "Aboort failed for i = " << j << std::endl;
}
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, key_blob_, params, &out_params));
AbortIfNeeded();
}
@@ -7501,7 +7501,7 @@
AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
AuthorizationSet out_params;
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, cipher_params, &out_params));
string plain_message = std::string(1 << msg_size, 'x');
string encrypted_message;
@@ -7512,7 +7512,7 @@
<< "Encrypt finish returned OK, but did not consume all of the given input";
cipher_params.push_back(out_params);
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, cipher_params));
string decrypted_message;
rc = Finish(encrypted_message, &decrypted_message);
@@ -7678,7 +7678,7 @@
if (curve != localCurve) {
// If the keys are using different curves KeyMint should fail with
// ErrorCode:INVALID_ARGUMENT. Check that.
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
string ZabFromKeyMintStr;
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
Finish(string(localPublicKey.begin(), localPublicKey.end()),
@@ -7818,7 +7818,7 @@
vector<uint8_t> encodedPublicKey;
GenerateLocalEcKey(localCurve, &privKey, &encodedPublicKey);
- EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
+ ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::AGREE_KEY, AuthorizationSetBuilder()));
string ZabFromKeyMintStr;
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT,
Finish(string(encodedPublicKey.begin(), encodedPublicKey.end()),
diff --git a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
index e630f70..c9a156d 100644
--- a/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
+++ b/security/keymint/aidl/vts/functional/SecureElementProvisioningTest.cpp
@@ -36,6 +36,8 @@
using std::shared_ptr;
using std::vector;
+constexpr int kRoTVersion1 = 40001;
+
class SecureElementProvisioningTest : public testing::Test {
protected:
static void SetUpTestSuite() {
@@ -57,6 +59,83 @@
}
}
+ void validateMacedRootOfTrust(const vector<uint8_t>& rootOfTrust) {
+ SCOPED_TRACE(testing::Message() << "RoT: " << bin2hex(rootOfTrust));
+
+ const auto [macItem, macEndPos, macErrMsg] = cppbor::parse(rootOfTrust);
+ ASSERT_TRUE(macItem) << "Root of trust parsing failed: " << macErrMsg;
+ ASSERT_EQ(macItem->semanticTagCount(), 1);
+ ASSERT_EQ(macItem->semanticTag(0), cppcose::kCoseMac0SemanticTag);
+ ASSERT_TRUE(macItem->asArray());
+ ASSERT_EQ(macItem->asArray()->size(), cppcose::kCoseMac0EntryCount);
+
+ const auto& protectedItem = macItem->asArray()->get(cppcose::kCoseMac0ProtectedParams);
+ ASSERT_TRUE(protectedItem);
+ ASSERT_TRUE(protectedItem->asBstr());
+ const auto [protMap, protEndPos, protErrMsg] = cppbor::parse(protectedItem->asBstr());
+ ASSERT_TRUE(protMap);
+ ASSERT_TRUE(protMap->asMap());
+ ASSERT_EQ(protMap->asMap()->size(), 1);
+
+ const auto& algorithm = protMap->asMap()->get(cppcose::ALGORITHM);
+ ASSERT_TRUE(algorithm);
+ ASSERT_TRUE(algorithm->asInt());
+ ASSERT_EQ(algorithm->asInt()->value(), cppcose::HMAC_256);
+
+ const auto& unprotItem = macItem->asArray()->get(cppcose::kCoseMac0UnprotectedParams);
+ ASSERT_TRUE(unprotItem);
+ ASSERT_TRUE(unprotItem->asMap());
+ ASSERT_EQ(unprotItem->asMap()->size(), 0);
+
+ const auto& payload = macItem->asArray()->get(cppcose::kCoseMac0Payload);
+ ASSERT_TRUE(payload);
+ ASSERT_TRUE(payload->asBstr());
+ validateRootOfTrust(payload->asBstr()->value());
+
+ const auto& tag = macItem->asArray()->get(cppcose::kCoseMac0Tag);
+ ASSERT_TRUE(tag);
+ ASSERT_TRUE(tag->asBstr());
+ ASSERT_EQ(tag->asBstr()->value().size(), 32);
+ // Cannot validate tag correctness. Only the secure side has the necessary key.
+ }
+
+ void validateRootOfTrust(const vector<uint8_t>& payload) {
+ SCOPED_TRACE(testing::Message() << "RoT payload: " << bin2hex(payload));
+
+ const auto [rot, rotPos, rotErrMsg] = cppbor::parse(payload);
+ ASSERT_TRUE(rot);
+ ASSERT_EQ(rot->semanticTagCount(), 1);
+ ASSERT_EQ(rot->semanticTag(), kRoTVersion1);
+ ASSERT_TRUE(rot->asArray());
+ ASSERT_EQ(rot->asArray()->size(), 5);
+
+ size_t pos = 0;
+
+ const auto& vbKey = rot->asArray()->get(pos++);
+ ASSERT_TRUE(vbKey);
+ ASSERT_TRUE(vbKey->asBstr());
+
+ const auto& deviceLocked = rot->asArray()->get(pos++);
+ ASSERT_TRUE(deviceLocked);
+ ASSERT_TRUE(deviceLocked->asBool());
+
+ const auto& verifiedBootState = rot->asArray()->get(pos++);
+ ASSERT_TRUE(verifiedBootState);
+ ASSERT_TRUE(verifiedBootState->asInt());
+
+ const auto& verifiedBootHash = rot->asArray()->get(pos++);
+ ASSERT_TRUE(verifiedBootHash);
+ ASSERT_TRUE(verifiedBootHash->asBstr());
+
+ const auto& bootPatchLevel = rot->asArray()->get(pos++);
+ ASSERT_TRUE(bootPatchLevel);
+ ASSERT_TRUE(bootPatchLevel->asInt());
+
+ verify_root_of_trust(vbKey->asBstr()->value(), deviceLocked->asBool()->value(),
+ static_cast<VerifiedBoot>(verifiedBootState->asInt()->value()),
+ verifiedBootHash->asBstr()->value());
+ }
+
int32_t AidlVersion(shared_ptr<IKeyMintDevice> keymint) {
int32_t version = 0;
auto status = keymint->getInterfaceVersion(&version);
@@ -96,29 +175,19 @@
vector<uint8_t> rootOfTrust1;
Status result = tee->getRootOfTrust(challenge1, &rootOfTrust1);
-
- // TODO: Remove the next line to require TEEs to succeed.
- if (!result.isOk()) return;
-
- ASSERT_TRUE(result.isOk());
-
- // TODO: Parse and validate rootOfTrust1 here
+ ASSERT_TRUE(result.isOk()) << "getRootOfTrust returned " << result.getServiceSpecificError();
+ validateMacedRootOfTrust(rootOfTrust1);
vector<uint8_t> rootOfTrust2;
result = tee->getRootOfTrust(challenge2, &rootOfTrust2);
ASSERT_TRUE(result.isOk());
-
- // TODO: Parse and validate rootOfTrust2 here
-
+ validateMacedRootOfTrust(rootOfTrust2);
ASSERT_NE(rootOfTrust1, rootOfTrust2);
vector<uint8_t> rootOfTrust3;
result = tee->getRootOfTrust(challenge1, &rootOfTrust3);
ASSERT_TRUE(result.isOk());
-
ASSERT_EQ(rootOfTrust1, rootOfTrust3);
-
- // TODO: Parse and validate rootOfTrust3 here
}
TEST_F(SecureElementProvisioningTest, TeeDoesNotImplementStrongBoxMethods) {
@@ -252,7 +321,7 @@
result = tee->getRootOfTrust(challenge, &rootOfTrust);
ASSERT_TRUE(result.isOk());
- // TODO: Verify COSE_Mac0 structure and content here.
+ validateMacedRootOfTrust(rootOfTrust);
result = sb->sendRootOfTrust(rootOfTrust);
ASSERT_TRUE(result.isOk());
@@ -296,6 +365,8 @@
result = tee->getRootOfTrust(challenge, &rootOfTrust);
ASSERT_TRUE(result.isOk());
+ validateMacedRootOfTrust(rootOfTrust);
+
vector<uint8_t> corruptedRootOfTrust = rootOfTrust;
corruptedRootOfTrust[corruptedRootOfTrust.size() / 2]++;
result = sb->sendRootOfTrust(corruptedRootOfTrust);
diff --git a/wifi/1.6/default/ringbuffer.cpp b/wifi/1.6/default/ringbuffer.cpp
index 6d4ed84..981bf7b 100644
--- a/wifi/1.6/default/ringbuffer.cpp
+++ b/wifi/1.6/default/ringbuffer.cpp
@@ -26,20 +26,26 @@
Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
-void Ringbuffer::append(const std::vector<uint8_t>& input) {
+enum Ringbuffer::AppendStatus Ringbuffer::append(const std::vector<uint8_t>& input) {
if (input.size() == 0) {
- return;
+ return AppendStatus::FAIL_IP_BUFFER_ZERO;
}
if (input.size() > maxSize_) {
LOG(INFO) << "Oversized message of " << input.size() << " bytes is dropped";
- return;
+ return AppendStatus::FAIL_IP_BUFFER_EXCEEDED_MAXSIZE;
}
data_.push_back(input);
size_ += input.size() * sizeof(input[0]);
while (size_ > maxSize_) {
+ if (data_.front().size() <= 0 || data_.front().size() > maxSize_) {
+ LOG(ERROR) << "First buffer in the ring buffer is Invalid. Size: "
+ << data_.front().size();
+ return AppendStatus::FAIL_RING_BUFFER_CORRUPTED;
+ }
size_ -= data_.front().size() * sizeof(data_.front()[0]);
data_.pop_front();
}
+ return AppendStatus::SUCCESS;
}
const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
diff --git a/wifi/1.6/default/ringbuffer.h b/wifi/1.6/default/ringbuffer.h
index 8571a9f..c6a1e4c 100644
--- a/wifi/1.6/default/ringbuffer.h
+++ b/wifi/1.6/default/ringbuffer.h
@@ -31,11 +31,19 @@
*/
class Ringbuffer {
public:
+ // Error codes for the append ring buffer operation
+ enum AppendStatus {
+ SUCCESS,
+ FAIL_GENERIC,
+ FAIL_IP_BUFFER_ZERO,
+ FAIL_IP_BUFFER_EXCEEDED_MAXSIZE,
+ FAIL_RING_BUFFER_CORRUPTED
+ };
explicit Ringbuffer(size_t maxSize);
// Appends the data buffer and deletes from the front until buffer is
// within |maxSize_|.
- void append(const std::vector<uint8_t>& input);
+ enum AppendStatus append(const std::vector<uint8_t>& input);
const std::list<std::vector<uint8_t>>& getData() const;
void clear();
diff --git a/wifi/1.6/default/wifi_chip.cpp b/wifi/1.6/default/wifi_chip.cpp
index f062409..c7c00b1 100644
--- a/wifi/1.6/default/wifi_chip.cpp
+++ b/wifi/1.6/default/wifi_chip.cpp
@@ -1613,6 +1613,7 @@
return;
}
WifiDebugRingBufferStatus hidl_status;
+ Ringbuffer::AppendStatus appendstatus;
if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(status,
&hidl_status)) {
LOG(ERROR) << "Error converting ring buffer status";
@@ -1623,13 +1624,19 @@
const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
if (target != shared_ptr_this->ringbuffer_map_.end()) {
Ringbuffer& cur_buffer = target->second;
- cur_buffer.append(data);
+ appendstatus = cur_buffer.append(data);
} else {
LOG(ERROR) << "Ringname " << name << " not found";
return;
}
// unique_lock unlocked here
}
+ if (appendstatus == Ringbuffer::AppendStatus::FAIL_RING_BUFFER_CORRUPTED) {
+ LOG(ERROR) << "Ringname " << name << " is corrupted. Clear the ring buffer";
+ shared_ptr_this->writeRingbufferFilesInternal();
+ return;
+ }
+
};
legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->registerRingBufferCallbackHandler(
getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
@@ -1971,6 +1978,11 @@
}
unique_fd file_auto_closer(dump_fd);
for (const auto& cur_block : cur_buffer.getData()) {
+ if (cur_block.size() <= 0 || cur_block.size() > kMaxBufferSizeBytes) {
+ PLOG(ERROR) << "Ring buffer: " << item.first
+ << " is corrupted. Invalid block size: " << cur_block.size();
+ break;
+ }
if (write(dump_fd, cur_block.data(), sizeof(cur_block[0]) * cur_block.size()) ==
-1) {
PLOG(ERROR) << "Error writing to file";