Merge "Power: add a DISPLAY_CHANGE mode" into main
diff --git a/apexkey/OWNERS b/apexkey/OWNERS
new file mode 100644
index 0000000..38765f9
--- /dev/null
+++ b/apexkey/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 296524155
+
+jooyung@google.com
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index 9131935..635a25b 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -237,7 +237,7 @@
c.ports.push_back(primaryOutMix);
AudioPort primaryInMix =
- createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(0, 0));
+ createPort(c.nextPortId++, "primary input", 0, true, createPortMixExt(0, 1));
primaryInMix.profiles.push_back(
createProfile(PcmType::INT_16_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
@@ -252,14 +252,14 @@
c.ports.push_back(telephonyTxOutMix);
AudioPort telephonyRxInMix =
- createPort(c.nextPortId++, "telephony_rx", 0, true, createPortMixExt(1, 1));
+ createPort(c.nextPortId++, "telephony_rx", 0, true, createPortMixExt(0, 1));
telephonyRxInMix.profiles.insert(telephonyRxInMix.profiles.begin(),
standardPcmAudioProfiles.begin(),
standardPcmAudioProfiles.end());
c.ports.push_back(telephonyRxInMix);
AudioPort fmTunerInMix =
- createPort(c.nextPortId++, "fm_tuner", 0, true, createPortMixExt(1, 1));
+ createPort(c.nextPortId++, "fm_tuner", 0, true, createPortMixExt(0, 1));
fmTunerInMix.profiles.insert(fmTunerInMix.profiles.begin(),
standardPcmAudioProfiles.begin(),
standardPcmAudioProfiles.end());
@@ -285,6 +285,20 @@
return std::make_unique<Configuration>(configuration);
}
+// Note: When transitioning to loading of XML configs, either keep the configuration
+// of the remote submix sources from this static configuration, or update the XML
+// config to match it. There are two reasons for that:
+// 1. The canonical r_submix configuration only lists 'STEREO' and '48000',
+// however the framework attempts to open streams for other sample rates
+// as well. The legacy r_submix implementation allowed that, but libaudiohal@aidl
+// will not find a mix port to use. Because of that, list all channel
+// masks and sample rates that the legacy implementation allowed.
+// 2. The legacy implementation had a hard limit on the number of routes (10),
+// and this is checked indirectly by AudioPlaybackCaptureTest#testPlaybackCaptureDoS
+// CTS test. Instead of hardcoding the number of routes, we can use
+// "maxOpen/ActiveStreamCount" to enforce a similar limit. However, the canonical
+// XML file lacks this specification.
+//
// Remote Submix configuration:
//
// Device ports:
@@ -294,16 +308,10 @@
// - no profiles specified
//
// Mix ports:
-// * "r_submix output", unlimited max open, unlimited max active stream
+// * "r_submix output", maximum 20 opened streams, maximum 10 active streams
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 32-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 32-bit float; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// * "r_submix input", unlimited max open, unlimited max active stream
+// * "r_submix input", maximum 20 opened streams, maximum 10 active streams
// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 32-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 32-bit float; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
//
// Routes:
// "r_submix output" -> "Remote Submix Out"
@@ -313,15 +321,6 @@
static const Configuration configuration = []() {
Configuration c;
const std::vector<AudioProfile> standardPcmAudioProfiles{
- createProfile(PcmType::FLOAT_32_BIT,
- {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
- {8000, 11025, 16000, 32000, 44100, 48000}),
- createProfile(PcmType::INT_32_BIT,
- {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
- {8000, 11025, 16000, 32000, 44100, 48000}),
- createProfile(PcmType::INT_24_BIT,
- {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
- {8000, 11025, 16000, 32000, 44100, 48000}),
createProfile(PcmType::INT_16_BIT,
{AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
{8000, 11025, 16000, 32000, 44100, 48000})};
@@ -332,25 +331,25 @@
createPort(c.nextPortId++, "Remote Submix Out", 0, false,
createDeviceExt(AudioDeviceType::OUT_SUBMIX, 0,
AudioDeviceDescription::CONNECTION_VIRTUAL));
+ rsubmixOutDevice.profiles = standardPcmAudioProfiles;
c.ports.push_back(rsubmixOutDevice);
- c.connectedProfiles[rsubmixOutDevice.id] = standardPcmAudioProfiles;
AudioPort rsubmixInDevice =
createPort(c.nextPortId++, "Remote Submix In", 0, true,
createDeviceExt(AudioDeviceType::IN_SUBMIX, 0,
AudioDeviceDescription::CONNECTION_VIRTUAL));
+ rsubmixInDevice.profiles = standardPcmAudioProfiles;
c.ports.push_back(rsubmixInDevice);
- c.connectedProfiles[rsubmixInDevice.id] = standardPcmAudioProfiles;
// Mix ports
AudioPort rsubmixOutMix =
- createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(0, 0));
+ createPort(c.nextPortId++, "r_submix output", 0, false, createPortMixExt(20, 10));
rsubmixOutMix.profiles = standardPcmAudioProfiles;
c.ports.push_back(rsubmixOutMix);
AudioPort rsubmixInMix =
- createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(0, 0));
+ createPort(c.nextPortId++, "r_submix input", 0, true, createPortMixExt(20, 10));
rsubmixInMix.profiles = standardPcmAudioProfiles;
c.ports.push_back(rsubmixInMix);
@@ -442,7 +441,7 @@
c.ports.push_back(usbDeviceOutMix);
AudioPort usbDeviceInMix =
- createPort(c.nextPortId++, "usb_device input", 0, true, createPortMixExt(1, 1));
+ createPort(c.nextPortId++, "usb_device input", 0, true, createPortMixExt(0, 1));
c.ports.push_back(usbDeviceInMix);
c.routes.push_back(createRoute({usbDeviceOutMix}, usbOutDevice));
@@ -461,6 +460,10 @@
// - no profiles specified
// * "Test In", IN_AFE_PROXY
// - no profiles specified
+// * "Wired Headset", OUT_HEADSET
+// - profile PCM 24-bit; STEREO; 48000
+// * "Wired Headset Mic", IN_HEADSET
+// - profile PCM 24-bit; MONO; 48000
//
// Mix ports:
// * "test output", 1 max open, 1 max active stream
@@ -476,7 +479,8 @@
//
// Routes:
// "test output", "test fast output", "test compressed offload" -> "Test Out"
-// "Test In" -> "test input"
+// "test output" -> "Wired Headset"
+// "Test In", "Wired Headset Mic" -> "test input"
//
// Initial port configs:
// * "Test Out" device port: PCM 24-bit; STEREO; 48000
@@ -496,6 +500,14 @@
AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
createDeviceExt(AudioDeviceType::OUT_AFE_PROXY, 0)));
+ AudioPort headsetOutDevice =
+ createPort(c.nextPortId++, "Wired Headset", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_HEADSET, 0,
+ AudioDeviceDescription::CONNECTION_ANALOG));
+ headsetOutDevice.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_STEREO}, {48000}));
+ c.ports.push_back(headsetOutDevice);
+
AudioPort testInDevice = createPort(c.nextPortId++, "Test In", 0, true,
createDeviceExt(AudioDeviceType::IN_AFE_PROXY, 0));
c.ports.push_back(testInDevice);
@@ -504,6 +516,14 @@
AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
createDeviceExt(AudioDeviceType::IN_AFE_PROXY, 0)));
+ AudioPort headsetInDevice =
+ createPort(c.nextPortId++, "Wired Headset Mic", 0, true,
+ createDeviceExt(AudioDeviceType::IN_HEADSET, 0,
+ AudioDeviceDescription::CONNECTION_ANALOG));
+ headsetInDevice.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT, {AudioChannelLayout::LAYOUT_MONO}, {48000}));
+ c.ports.push_back(headsetInDevice);
+
// Mix ports
AudioPort testOutMix =
@@ -549,7 +569,8 @@
c.routes.push_back(
createRoute({testOutMix, testFastOutMix, compressedOffloadOutMix}, testOutDevice));
- c.routes.push_back(createRoute({testInDevice}, testInMIx));
+ c.routes.push_back(createRoute({testOutMix}, headsetOutDevice));
+ c.routes.push_back(createRoute({testInDevice, headsetInDevice}, testInMIx));
c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index cd2ba53..47ba9f4 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -48,6 +48,8 @@
mPriority = priority;
{
std::lock_guard lg(mThreadMutex);
+ mStop = true;
+ mExit = false;
mThreadContext = std::move(context);
auto statusMQ = mThreadContext->getStatusFmq();
EventFlag* efGroup = nullptr;
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index b7761bf..76132b3 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -340,21 +340,43 @@
ndk::ScopedAStatus Module::updateStreamsConnectedState(const AudioPatch& oldPatch,
const AudioPatch& newPatch) {
- // Streams from the old patch need to be disconnected, streams from the new
- // patch need to be connected. If the stream belongs to both patches, no need
- // to update it.
+ // Notify streams about the new set of devices they are connected to.
auto maybeFailure = ndk::ScopedAStatus::ok();
- std::set<int32_t> idsToDisconnect, idsToConnect, idsToDisconnectOnFailure;
- idsToDisconnect.insert(oldPatch.sourcePortConfigIds.begin(),
- oldPatch.sourcePortConfigIds.end());
- idsToDisconnect.insert(oldPatch.sinkPortConfigIds.begin(), oldPatch.sinkPortConfigIds.end());
- idsToConnect.insert(newPatch.sourcePortConfigIds.begin(), newPatch.sourcePortConfigIds.end());
- idsToConnect.insert(newPatch.sinkPortConfigIds.begin(), newPatch.sinkPortConfigIds.end());
- std::for_each(idsToDisconnect.begin(), idsToDisconnect.end(), [&](const auto& portConfigId) {
- if (idsToConnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
- if (auto status = mStreams.setStreamConnectedDevices(portConfigId, {}); status.isOk()) {
+ using Connections =
+ std::map<int32_t /*mixPortConfigId*/, std::set<int32_t /*devicePortConfigId*/>>;
+ Connections oldConnections, newConnections;
+ auto fillConnectionsHelper = [&](Connections& connections,
+ const std::vector<int32_t>& mixPortCfgIds,
+ const std::vector<int32_t>& devicePortCfgIds) {
+ for (int32_t mixPortCfgId : mixPortCfgIds) {
+ connections[mixPortCfgId].insert(devicePortCfgIds.begin(), devicePortCfgIds.end());
+ }
+ };
+ auto fillConnections = [&](Connections& connections, const AudioPatch& patch) {
+ if (std::find_if(patch.sourcePortConfigIds.begin(), patch.sourcePortConfigIds.end(),
+ [&](int32_t portConfigId) { return mStreams.count(portConfigId) > 0; }) !=
+ patch.sourcePortConfigIds.end()) {
+ // Sources are mix ports.
+ fillConnectionsHelper(connections, patch.sourcePortConfigIds, patch.sinkPortConfigIds);
+ } else if (std::find_if(patch.sinkPortConfigIds.begin(), patch.sinkPortConfigIds.end(),
+ [&](int32_t portConfigId) {
+ return mStreams.count(portConfigId) > 0;
+ }) != patch.sinkPortConfigIds.end()) {
+ // Sources are device ports.
+ fillConnectionsHelper(connections, patch.sinkPortConfigIds, patch.sourcePortConfigIds);
+ } // Otherwise, there are no streams to notify.
+ };
+ fillConnections(oldConnections, oldPatch);
+ fillConnections(newConnections, newPatch);
+
+ std::for_each(oldConnections.begin(), oldConnections.end(), [&](const auto& connectionPair) {
+ const int32_t mixPortConfigId = connectionPair.first;
+ if (auto it = newConnections.find(mixPortConfigId);
+ it == newConnections.end() || it->second != connectionPair.second) {
+ if (auto status = mStreams.setStreamConnectedDevices(mixPortConfigId, {});
+ status.isOk()) {
LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
- << portConfigId << " has been disconnected";
+ << mixPortConfigId << " has been disconnected";
} else {
// Disconnection is tricky to roll back, just register a failure.
maybeFailure = std::move(status);
@@ -362,23 +384,26 @@
}
});
if (!maybeFailure.isOk()) return maybeFailure;
- std::for_each(idsToConnect.begin(), idsToConnect.end(), [&](const auto& portConfigId) {
- if (idsToDisconnect.count(portConfigId) == 0 && mStreams.count(portConfigId) != 0) {
- const auto connectedDevices = findConnectedDevices(portConfigId);
+ std::set<int32_t> idsToDisconnectOnFailure;
+ std::for_each(newConnections.begin(), newConnections.end(), [&](const auto& connectionPair) {
+ const int32_t mixPortConfigId = connectionPair.first;
+ if (auto it = oldConnections.find(mixPortConfigId);
+ it == oldConnections.end() || it->second != connectionPair.second) {
+ const auto connectedDevices = findConnectedDevices(mixPortConfigId);
if (connectedDevices.empty()) {
// This is important as workers use the vector size to derive the connection status.
LOG(FATAL) << "updateStreamsConnectedState: No connected devices found for port "
"config id "
- << portConfigId;
+ << mixPortConfigId;
}
- if (auto status = mStreams.setStreamConnectedDevices(portConfigId, connectedDevices);
+ if (auto status = mStreams.setStreamConnectedDevices(mixPortConfigId, connectedDevices);
status.isOk()) {
LOG(DEBUG) << "updateStreamsConnectedState: The stream on port config id "
- << portConfigId << " has been connected to: "
+ << mixPortConfigId << " has been connected to: "
<< ::android::internal::ToString(connectedDevices);
} else {
maybeFailure = std::move(status);
- idsToDisconnectOnFailure.insert(portConfigId);
+ idsToDisconnectOnFailure.insert(mixPortConfigId);
}
}
});
@@ -515,9 +540,9 @@
}
}
- connectedPort.id = ++getConfig().nextPortId;
+ connectedPort.id = getConfig().nextPortId++;
auto [connectedPortsIt, _] =
- mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::vector<int32_t>()));
+ mConnectedDevicePorts.insert(std::pair(connectedPort.id, std::set<int32_t>()));
LOG(DEBUG) << __func__ << ": template port " << templateId << " external device connected, "
<< "connected port ID " << connectedPort.id;
ports.push_back(connectedPort);
@@ -550,9 +575,21 @@
// of all profiles from all routable dynamic device ports would be more involved.
for (const auto mixPortId : routablePortIds) {
auto portsIt = findById<AudioPort>(ports, mixPortId);
- if (portsIt != ports.end() && portsIt->profiles.empty()) {
- portsIt->profiles = connectedPort.profiles;
- connectedPortsIt->second.push_back(portsIt->id);
+ if (portsIt != ports.end()) {
+ if (portsIt->profiles.empty()) {
+ portsIt->profiles = connectedPort.profiles;
+ connectedPortsIt->second.insert(portsIt->id);
+ } else {
+ // Check if profiles are non empty because they were populated by
+ // a previous connection. Otherwise, it means that they are not empty because
+ // the mix port has static profiles.
+ for (const auto cp : mConnectedDevicePorts) {
+ if (cp.second.count(portsIt->id) > 0) {
+ connectedPortsIt->second.insert(portsIt->id);
+ break;
+ }
+ }
+ }
}
}
*_aidl_return = std::move(connectedPort);
@@ -607,13 +644,20 @@
}
}
- for (const auto mixPortId : connectedPortsIt->second) {
+ // Clear profiles for mix ports that are not connected to any other ports.
+ std::set<int32_t> mixPortsToClear = std::move(connectedPortsIt->second);
+ mConnectedDevicePorts.erase(connectedPortsIt);
+ for (const auto& connectedPort : mConnectedDevicePorts) {
+ for (int32_t mixPortId : connectedPort.second) {
+ mixPortsToClear.erase(mixPortId);
+ }
+ }
+ for (int32_t mixPortId : mixPortsToClear) {
auto mixPortIt = findById<AudioPort>(ports, mixPortId);
if (mixPortIt != ports.end()) {
mixPortIt->profiles = {};
}
}
- mConnectedDevicePorts.erase(connectedPortsIt);
return ndk::ScopedAStatus::ok();
}
@@ -846,6 +890,7 @@
patches.push_back(*_aidl_return);
} else {
oldPatch = *existing;
+ *existing = *_aidl_return;
}
patchesBackup = mPatches;
registerPatch(*_aidl_return);
@@ -1258,6 +1303,12 @@
mmapSources.insert(port.id);
}
}
+ if (mmapSources.empty() && mmapSinks.empty()) {
+ AudioMMapPolicyInfo never;
+ never.mmapPolicy = AudioMMapPolicy::NEVER;
+ _aidl_return->push_back(never);
+ return ndk::ScopedAStatus::ok();
+ }
for (const auto& route : getConfig().routes) {
if (mmapSinks.count(route.sinkPortId) != 0) {
// The sink is a mix port, add the sources if they are device ports.
diff --git a/audio/aidl/default/alsa/ModuleAlsa.cpp b/audio/aidl/default/alsa/ModuleAlsa.cpp
index 8e75d56..8512631 100644
--- a/audio/aidl/default/alsa/ModuleAlsa.cpp
+++ b/audio/aidl/default/alsa/ModuleAlsa.cpp
@@ -39,13 +39,14 @@
if (!deviceProfile.has_value()) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- auto profile = alsa::readAlsaDeviceInfo(*deviceProfile);
- if (!profile.has_value()) {
+ auto proxy = alsa::readAlsaDeviceInfo(*deviceProfile);
+ if (proxy.get() == nullptr) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
- std::vector<AudioChannelLayout> channels = alsa::getChannelMasksFromProfile(&profile.value());
- std::vector<int> sampleRates = alsa::getSampleRatesFromProfile(&profile.value());
+ alsa_device_profile* profile = proxy.getProfile();
+ std::vector<AudioChannelLayout> channels = alsa::getChannelMasksFromProfile(profile);
+ std::vector<int> sampleRates = alsa::getSampleRatesFromProfile(profile);
for (size_t i = 0; i < std::min(MAX_PROFILE_FORMATS, AUDIO_PORT_MAX_AUDIO_PROFILES) &&
profile->formats[i] != PCM_FORMAT_INVALID;
diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp
index 0605d6f..403b94b 100644
--- a/audio/aidl/default/alsa/StreamAlsa.cpp
+++ b/audio/aidl/default/alsa/StreamAlsa.cpp
@@ -83,7 +83,7 @@
proxy = alsa::openProxyForAttachedDevice(
device, const_cast<struct pcm_config*>(&mConfig.value()), mBufferSizeFrames);
}
- if (!proxy) {
+ if (proxy.get() == nullptr) {
return ::android::NO_INIT;
}
alsaDeviceProxies.push_back(std::move(proxy));
diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp
index 9dcd024..c08836c 100644
--- a/audio/aidl/default/alsa/Utils.cpp
+++ b/audio/aidl/default/alsa/Utils.cpp
@@ -37,6 +37,23 @@
namespace aidl::android::hardware::audio::core::alsa {
+DeviceProxy::DeviceProxy() : mProfile(nullptr), mProxy(nullptr, alsaProxyDeleter) {}
+
+DeviceProxy::DeviceProxy(const DeviceProfile& deviceProfile)
+ : mProfile(new alsa_device_profile), mProxy(new alsa_device_proxy, alsaProxyDeleter) {
+ profile_init(mProfile.get(), deviceProfile.direction);
+ mProfile->card = deviceProfile.card;
+ mProfile->device = deviceProfile.device;
+ memset(mProxy.get(), 0, sizeof(alsa_device_proxy));
+}
+
+void DeviceProxy::alsaProxyDeleter(alsa_device_proxy* proxy) {
+ if (proxy != nullptr) {
+ proxy_close(proxy);
+ delete proxy;
+ }
+}
+
namespace {
using AudioChannelCountToMaskMap = std::map<unsigned int, AudioChannelLayout>;
@@ -261,39 +278,24 @@
return sampleRates;
}
-DeviceProxy makeDeviceProxy() {
- DeviceProxy proxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) {
- if (proxy != nullptr) {
- proxy_close(proxy);
- delete proxy;
- }
- });
- memset(proxy.get(), 0, sizeof(alsa_device_proxy));
- return proxy;
-}
-
DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
struct pcm_config* pcmConfig, size_t bufferFrameCount) {
if (deviceProfile.isExternal) {
LOG(FATAL) << __func__ << ": called for an external device, address=" << deviceProfile;
}
- alsa_device_profile profile;
- profile_init(&profile, deviceProfile.direction);
- profile.card = deviceProfile.card;
- profile.device = deviceProfile.device;
- if (!profile_fill_builtin_device_info(&profile, pcmConfig, bufferFrameCount)) {
+ DeviceProxy proxy(deviceProfile);
+ if (!profile_fill_builtin_device_info(proxy.getProfile(), pcmConfig, bufferFrameCount)) {
LOG(FATAL) << __func__ << ": failed to init for built-in device, address=" << deviceProfile;
}
- auto proxy = makeDeviceProxy();
- if (int err = proxy_prepare_from_default_config(proxy.get(), &profile); err != 0) {
+ if (int err = proxy_prepare_from_default_config(proxy.get(), proxy.getProfile()); err != 0) {
LOG(FATAL) << __func__ << ": fail to prepare for device address=" << deviceProfile
<< " error=" << err;
- return nullptr;
+ return DeviceProxy();
}
if (int err = proxy_open(proxy.get()); err != 0) {
LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
<< " error=" << err;
- return nullptr;
+ return DeviceProxy();
}
return proxy;
}
@@ -303,42 +305,36 @@
if (!deviceProfile.isExternal) {
LOG(FATAL) << __func__ << ": called for an attached device, address=" << deviceProfile;
}
- auto profile = readAlsaDeviceInfo(deviceProfile);
- if (!profile.has_value()) {
- LOG(ERROR) << __func__ << ": unable to read device info, device address=" << deviceProfile;
- return nullptr;
+ auto proxy = readAlsaDeviceInfo(deviceProfile);
+ if (proxy.get() == nullptr) {
+ return proxy;
}
- auto proxy = makeDeviceProxy();
- if (int err = proxy_prepare(proxy.get(), &profile.value(), pcmConfig, requireExactMatch);
+ if (int err = proxy_prepare(proxy.get(), proxy.getProfile(), pcmConfig, requireExactMatch);
err != 0) {
LOG(ERROR) << __func__ << ": fail to prepare for device address=" << deviceProfile
<< " error=" << err;
- return nullptr;
+ return DeviceProxy();
}
if (int err = proxy_open(proxy.get()); err != 0) {
LOG(ERROR) << __func__ << ": failed to open device, address=" << deviceProfile
<< " error=" << err;
- return nullptr;
+ return DeviceProxy();
}
return proxy;
}
-std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
- alsa_device_profile profile;
- profile_init(&profile, deviceProfile.direction);
- profile.card = deviceProfile.card;
- profile.device = deviceProfile.device;
- if (!profile_read_device_info(&profile)) {
- LOG(ERROR) << __func__ << ": failed to read device info, card=" << profile.card
- << ", device=" << profile.device;
- return std::nullopt;
+DeviceProxy readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
+ DeviceProxy proxy(deviceProfile);
+ if (!profile_read_device_info(proxy.getProfile())) {
+ LOG(ERROR) << __func__ << ": unable to read device info, device address=" << deviceProfile;
+ return DeviceProxy();
}
- return profile;
+ return proxy;
}
void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames) {
- if (proxy != nullptr) {
- proxy->transferred = frames;
+ if (proxy.get() != nullptr) {
+ proxy.get()->transferred = frames;
}
}
diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h
index 37414b3..980f685 100644
--- a/audio/aidl/default/alsa/Utils.h
+++ b/audio/aidl/default/alsa/Utils.h
@@ -43,8 +43,21 @@
bool isExternal;
};
std::ostream& operator<<(std::ostream& os, const DeviceProfile& device);
-using DeviceProxyDeleter = std::function<void(alsa_device_proxy*)>;
-using DeviceProxy = std::unique_ptr<alsa_device_proxy, DeviceProxyDeleter>;
+
+class DeviceProxy {
+ public:
+ DeviceProxy(); // Constructs a "null" proxy.
+ explicit DeviceProxy(const DeviceProfile& deviceProfile);
+ alsa_device_profile* getProfile() { return mProfile.get(); }
+ alsa_device_proxy* get() { return mProxy.get(); }
+
+ private:
+ static void alsaProxyDeleter(alsa_device_proxy* proxy);
+ using AlsaProxy = std::unique_ptr<alsa_device_proxy, decltype(alsaProxyDeleter)*>;
+
+ std::unique_ptr<alsa_device_profile> mProfile;
+ AlsaProxy mProxy;
+};
::aidl::android::media::audio::common::AudioChannelLayout getChannelLayoutMaskFromChannelCount(
unsigned int channelCount, int isInput);
@@ -60,12 +73,11 @@
const ::aidl::android::media::audio::common::AudioPort& audioPort);
std::optional<struct pcm_config> getPcmConfig(const StreamContext& context, bool isInput);
std::vector<int> getSampleRatesFromProfile(const alsa_device_profile* profile);
-DeviceProxy makeDeviceProxy();
DeviceProxy openProxyForAttachedDevice(const DeviceProfile& deviceProfile,
struct pcm_config* pcmConfig, size_t bufferFrameCount);
DeviceProxy openProxyForExternalDevice(const DeviceProfile& deviceProfile,
struct pcm_config* pcmConfig, bool requireExactMatch);
-std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
+DeviceProxy readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
void resetTransferredFrames(DeviceProxy& proxy, uint64_t frames);
::aidl::android::media::audio::common::AudioFormatDescription
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index fb3eef2..bfdab51 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -142,7 +142,7 @@
// ids of device ports created at runtime via 'connectExternalDevice'.
// Also stores a list of ids of mix ports with dynamic profiles that were populated from
// the connected port. This list can be empty, thus an int->int multimap can't be used.
- using ConnectedDevicePorts = std::map<int32_t, std::vector<int32_t>>;
+ using ConnectedDevicePorts = std::map<int32_t, std::set<int32_t>>;
// Maps port ids and port config ids to patch ids.
// Multimap because both ports and configs can be used by multiple patches.
using Patches = std::multimap<int32_t, int32_t>;
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index f7cf4ce..a2f0260 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -26,7 +26,10 @@
"libaudioaidlcommon",
"libaidlcommonsupport",
],
- header_libs: ["libaudioaidl_headers"],
+ header_libs: [
+ "libaudioaidl_headers",
+ "libexpectedutils_headers",
+ ],
cflags: [
"-Wall",
"-Wextra",
diff --git a/audio/aidl/vts/ModuleConfig.cpp b/audio/aidl/vts/ModuleConfig.cpp
index 8fdb155..af3597d 100644
--- a/audio/aidl/vts/ModuleConfig.cpp
+++ b/audio/aidl/vts/ModuleConfig.cpp
@@ -21,6 +21,7 @@
#include <aidl/android/media/audio/common/AudioInputFlags.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
+#include <error/expected_utils.h>
#include "ModuleConfig.h"
@@ -499,18 +500,13 @@
return result;
}
-const ndk::ScopedAStatus& ModuleConfig::onExternalDeviceConnected(IModule* module,
- const AudioPort& port) {
- // Update ports and routes
- mStatus = module->getAudioPorts(&mPorts);
- if (!mStatus.isOk()) return mStatus;
- mStatus = module->getAudioRoutes(&mRoutes);
- if (!mStatus.isOk()) return mStatus;
+ndk::ScopedAStatus ModuleConfig::onExternalDeviceConnected(IModule* module, const AudioPort& port) {
+ RETURN_STATUS_IF_ERROR(module->getAudioPorts(&mPorts));
+ RETURN_STATUS_IF_ERROR(module->getAudioRoutes(&mRoutes));
// Validate port is present in module
if (std::find(mPorts.begin(), mPorts.end(), port) == mPorts.end()) {
- mStatus = ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- return mStatus;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) {
@@ -518,23 +514,20 @@
} else {
mConnectedExternalSinkDevicePorts.insert(port.id);
}
- return mStatus;
+ return ndk::ScopedAStatus::ok();
}
-const ndk::ScopedAStatus& ModuleConfig::onExternalDeviceDisconnected(IModule* module,
- const AudioPort& port) {
- // Update ports and routes
- mStatus = module->getAudioPorts(&mPorts);
- if (!mStatus.isOk()) return mStatus;
- mStatus = module->getAudioRoutes(&mRoutes);
- if (!mStatus.isOk()) return mStatus;
+ndk::ScopedAStatus ModuleConfig::onExternalDeviceDisconnected(IModule* module,
+ const AudioPort& port) {
+ RETURN_STATUS_IF_ERROR(module->getAudioPorts(&mPorts));
+ RETURN_STATUS_IF_ERROR(module->getAudioRoutes(&mRoutes));
if (port.flags.getTag() == aidl::android::media::audio::common::AudioIoFlags::Tag::input) {
mConnectedExternalSourceDevicePorts.erase(port.id);
} else {
mConnectedExternalSinkDevicePorts.erase(port.id);
}
- return mStatus;
+ return ndk::ScopedAStatus::ok();
}
bool ModuleConfig::isMmapSupported() const {
diff --git a/audio/aidl/vts/ModuleConfig.h b/audio/aidl/vts/ModuleConfig.h
index bce1de1..0cbf24d 100644
--- a/audio/aidl/vts/ModuleConfig.h
+++ b/audio/aidl/vts/ModuleConfig.h
@@ -157,10 +157,10 @@
return *config.begin();
}
- const ndk::ScopedAStatus& onExternalDeviceConnected(
+ ndk::ScopedAStatus onExternalDeviceConnected(
aidl::android::hardware::audio::core::IModule* module,
const aidl::android::media::audio::common::AudioPort& port);
- const ndk::ScopedAStatus& onExternalDeviceDisconnected(
+ ndk::ScopedAStatus onExternalDeviceDisconnected(
aidl::android::hardware::audio::core::IModule* module,
const aidl::android::media::audio::common::AudioPort& port);
diff --git a/audio/aidl/vts/TestUtils.h b/audio/aidl/vts/TestUtils.h
index 10c2fc6..b559669 100644
--- a/audio/aidl/vts/TestUtils.h
+++ b/audio/aidl/vts/TestUtils.h
@@ -78,9 +78,9 @@
EXPECT_PRED_FORMAT2(::android::hardware::audio::common::testing::detail::assertResult, \
expected, ret)
-#define SKIP_TEST_IF_DATA_UNSUPPORTED(flags) \
- ({ \
- if ((flags).hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL || (flags).bypass) { \
- GTEST_SKIP() << "Skip data path for offload"; \
- } \
+#define SKIP_TEST_IF_DATA_UNSUPPORTED(flags) \
+ ({ \
+ if ((flags).hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL || (flags).bypass) { \
+ GTEST_SKIP() << "Skip data path for offload"; \
+ } \
})
\ No newline at end of file
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 025056e..621d200 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -46,6 +46,7 @@
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include <android-base/chrono_utils.h>
#include <android/binder_enums.h>
+#include <error/expected_utils.h>
#include <fmq/AidlMessageQueue.h>
#include "AudioHalBinderServiceUtil.h"
@@ -86,6 +87,7 @@
using aidl::android::media::audio::common::AudioFormatType;
using aidl::android::media::audio::common::AudioIoFlags;
using aidl::android::media::audio::common::AudioLatencyMode;
+using aidl::android::media::audio::common::AudioMMapPolicy;
using aidl::android::media::audio::common::AudioMMapPolicyInfo;
using aidl::android::media::audio::common::AudioMMapPolicyType;
using aidl::android::media::audio::common::AudioMode;
@@ -144,28 +146,36 @@
}
AudioPort GenerateUniqueDeviceAddress(const AudioPort& port) {
+ // Point-to-point connections do not use addresses.
+ static const std::set<std::string> kPointToPointConnections = {
+ AudioDeviceDescription::CONNECTION_ANALOG, AudioDeviceDescription::CONNECTION_HDMI,
+ AudioDeviceDescription::CONNECTION_HDMI_ARC,
+ AudioDeviceDescription::CONNECTION_HDMI_EARC, AudioDeviceDescription::CONNECTION_SPDIF};
static int nextId = 0;
using Tag = AudioDeviceAddress::Tag;
+ const auto& deviceDescription = port.ext.get<AudioPortExt::Tag::device>().device.type;
AudioDeviceAddress address;
- switch (suggestDeviceAddressTag(port.ext.get<AudioPortExt::Tag::device>().device.type)) {
- case Tag::id:
- address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
- break;
- case Tag::mac:
- address = AudioDeviceAddress::make<Tag::mac>(
- std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
- break;
- case Tag::ipv4:
- address = AudioDeviceAddress::make<Tag::ipv4>(
- std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
- break;
- case Tag::ipv6:
- address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
- 0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
- break;
- case Tag::alsa:
- address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
- break;
+ if (kPointToPointConnections.count(deviceDescription.connection) == 0) {
+ switch (suggestDeviceAddressTag(deviceDescription)) {
+ case Tag::id:
+ address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
+ break;
+ case Tag::mac:
+ address = AudioDeviceAddress::make<Tag::mac>(
+ std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
+ break;
+ case Tag::ipv4:
+ address = AudioDeviceAddress::make<Tag::ipv4>(
+ std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
+ break;
+ case Tag::ipv6:
+ address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
+ 0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
+ break;
+ case Tag::alsa:
+ address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
+ break;
+ }
}
AudioPort result = port;
result.ext.get<AudioPortExt::Tag::device>().device.address = std::move(address);
@@ -412,9 +422,21 @@
void SetUpImpl(const std::string& moduleName) {
ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
+ ASSERT_IS_OK(module->getAudioPorts(&initialPorts));
+ ASSERT_IS_OK(module->getAudioRoutes(&initialRoutes));
}
- void TearDownImpl() { debug.reset(); }
+ void TearDownImpl() {
+ debug.reset();
+ std::vector<AudioPort> finalPorts;
+ ASSERT_IS_OK(module->getAudioPorts(&finalPorts));
+ EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioPort>(initialPorts, finalPorts))
+ << "The list of audio ports was not restored to the initial state";
+ std::vector<AudioRoute> finalRoutes;
+ ASSERT_IS_OK(module->getAudioRoutes(&finalRoutes));
+ EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioRoute>(initialRoutes, finalRoutes))
+ << "The list of audio routes was not restored to the initial state";
+ }
void ConnectToService(const std::string& moduleName) {
ASSERT_EQ(module, nullptr);
@@ -502,17 +524,24 @@
}
}
+ // Warning: modifies the vectors!
+ template <typename T>
+ void VerifyVectorsAreEqual(std::vector<T>& v1, std::vector<T>& v2) {
+ ASSERT_EQ(v1.size(), v2.size());
+ std::sort(v1.begin(), v1.end());
+ std::sort(v2.begin(), v2.end());
+ if (v1 != v2) {
+ FAIL() << "Vectors are not equal: v1 = " << ::android::internal::ToString(v1)
+ << ", v2 = " << ::android::internal::ToString(v2);
+ }
+ }
+
std::shared_ptr<IModule> module;
std::unique_ptr<ModuleConfig> moduleConfig;
AudioHalBinderServiceUtil binderUtil;
std::unique_ptr<WithDebugFlags> debug;
-};
-
-class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
- public:
- void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
-
- void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+ std::vector<AudioPort> initialPorts;
+ std::vector<AudioRoute> initialRoutes;
};
class WithDevicePortConnectedState {
@@ -530,16 +559,19 @@
<< "when external device disconnected";
}
}
+ ScopedAStatus SetUpNoChecks(IModule* module, ModuleConfig* moduleConfig) {
+ RETURN_STATUS_IF_ERROR(module->connectExternalDevice(mIdAndData, &mConnectedPort));
+ RETURN_STATUS_IF_ERROR(moduleConfig->onExternalDeviceConnected(module, mConnectedPort));
+ mModule = module;
+ mModuleConfig = moduleConfig;
+ return ScopedAStatus::ok();
+ }
void SetUp(IModule* module, ModuleConfig* moduleConfig) {
- ASSERT_IS_OK(module->connectExternalDevice(mIdAndData, &mConnectedPort))
+ ASSERT_NE(moduleConfig, nullptr);
+ ASSERT_IS_OK(SetUpNoChecks(module, moduleConfig))
<< "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";
- ASSERT_NE(moduleConfig, nullptr);
- ASSERT_IS_OK(moduleConfig->onExternalDeviceConnected(module, mConnectedPort))
- << "when external device connected";
- mModule = module;
- mModuleConfig = moduleConfig;
}
int32_t getId() const { return mConnectedPort.id; }
const AudioPort& get() { return mConnectedPort; }
@@ -551,6 +583,13 @@
AudioPort mConnectedPort;
};
+class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpImpl(GetParam())); }
+
+ void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownImpl()); }
+};
+
class StreamContext {
public:
typedef AidlMessageQueue<StreamDescriptor::Command, SynchronizedReadWrite> CommandMQ;
@@ -1199,11 +1238,25 @@
const AudioPortConfig& portConfig2)
: mSrcPortConfig(sinkIsCfg1 ? portConfig2 : portConfig1),
mSinkPortConfig(sinkIsCfg1 ? portConfig1 : portConfig2) {}
+ WithAudioPatch(const WithAudioPatch& patch, const AudioPortConfig& srcPortConfig,
+ const AudioPortConfig& sinkPortConfig)
+ : mInitialPatch(patch.mPatch),
+ mSrcPortConfig(srcPortConfig),
+ mSinkPortConfig(sinkPortConfig),
+ mModule(patch.mModule),
+ mPatch(patch.mPatch) {}
WithAudioPatch(const WithAudioPatch&) = delete;
WithAudioPatch& operator=(const WithAudioPatch&) = delete;
~WithAudioPatch() {
if (mModule != nullptr && mPatch.id != 0) {
- EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
+ if (mInitialPatch.has_value()) {
+ AudioPatch ignored;
+ // This releases our port configs so that they can be reset.
+ EXPECT_IS_OK(mModule->setAudioPatch(*mInitialPatch, &ignored))
+ << "patch id " << mInitialPatch->id;
+ } else {
+ EXPECT_IS_OK(mModule->resetAudioPatch(mPatch.id)) << "patch id " << getId();
+ }
}
}
void SetUpPortConfigs(IModule* module) {
@@ -1225,6 +1278,16 @@
EXPECT_GT(latencyMs, 0) << "patch id " << getId();
}
}
+ void VerifyAgainstAllPatches(IModule* module) {
+ std::vector<AudioPatch> allPatches;
+ ASSERT_IS_OK(module->getAudioPatches(&allPatches));
+ const auto& patchIt = findById(allPatches, getId());
+ ASSERT_NE(patchIt, allPatches.end()) << "patch id " << getId();
+ if (get() != *patchIt) {
+ FAIL() << "Stored patch: " << get().toString() << " is not the same as returned "
+ << "by the HAL module: " << patchIt->toString();
+ }
+ }
int32_t getId() const { return mPatch.id; }
const AudioPatch& get() const { return mPatch; }
const AudioPortConfig& getSinkPortConfig() const { return mSinkPortConfig.get(); }
@@ -1234,6 +1297,7 @@
}
private:
+ std::optional<AudioPatch> mInitialPatch;
WithAudioPortConfig mSrcPortConfig;
WithAudioPortConfig mSinkPortConfig;
IModule* mModule = nullptr;
@@ -1258,11 +1322,8 @@
ASSERT_IS_OK(module->getAudioPorts(&ports1));
std::vector<AudioPort> ports2;
ASSERT_IS_OK(module->getAudioPorts(&ports2));
- ASSERT_EQ(ports1.size(), ports2.size())
- << "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);
+ EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioPort>(ports1, ports2))
+ << "Audio port arrays do not match across consequent calls to getAudioPorts";
}
TEST_P(AudioCoreModule, GetAudioRoutesIsStable) {
@@ -1270,11 +1331,8 @@
ASSERT_IS_OK(module->getAudioRoutes(&routes1));
std::vector<AudioRoute> routes2;
ASSERT_IS_OK(module->getAudioRoutes(&routes2));
- ASSERT_EQ(routes1.size(), routes2.size())
- << "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);
+ EXPECT_NO_FATAL_FAILURE(VerifyVectorsAreEqual<AudioRoute>(routes1, routes2))
+ << " Audio route arrays do not match across consequent calls to getAudioRoutes";
}
TEST_P(AudioCoreModule, GetAudioRoutesAreValid) {
@@ -1792,39 +1850,151 @@
}
}
+class RoutedPortsProfilesSnapshot {
+ public:
+ explicit RoutedPortsProfilesSnapshot(int32_t portId) : mPortId(portId) {}
+ void Capture(IModule* module) {
+ std::vector<AudioRoute> routes;
+ ASSERT_IS_OK(module->getAudioRoutesForAudioPort(mPortId, &routes));
+ std::vector<AudioPort> allPorts;
+ ASSERT_IS_OK(module->getAudioPorts(&allPorts));
+ ASSERT_NO_FATAL_FAILURE(GetAllRoutedPorts(routes, allPorts));
+ ASSERT_NO_FATAL_FAILURE(GetProfileSizes());
+ }
+ void VerifyNoProfilesChanges(const RoutedPortsProfilesSnapshot& before) {
+ for (const auto& p : before.mRoutedPorts) {
+ auto beforeIt = before.mPortProfileSizes.find(p.id);
+ ASSERT_NE(beforeIt, before.mPortProfileSizes.end())
+ << "port ID " << p.id << " not found in the initial profile sizes";
+ EXPECT_EQ(beforeIt->second, mPortProfileSizes[p.id])
+ << " port " << p.toString() << " has an unexpected profile size change"
+ << " following an external device connection and disconnection";
+ }
+ }
+ void VerifyProfilesNonEmpty() {
+ for (const auto& p : mRoutedPorts) {
+ EXPECT_NE(0UL, mPortProfileSizes[p.id])
+ << " port " << p.toString() << " must have had its profiles"
+ << " populated while having a connected external device";
+ }
+ }
+
+ const std::vector<AudioPort>& getRoutedPorts() const { return mRoutedPorts; }
+
+ private:
+ void GetAllRoutedPorts(const std::vector<AudioRoute>& routes,
+ std::vector<AudioPort>& allPorts) {
+ for (const auto& r : routes) {
+ if (r.sinkPortId == mPortId) {
+ for (const auto& srcPortId : r.sourcePortIds) {
+ const auto srcPortIt = findById(allPorts, srcPortId);
+ ASSERT_NE(allPorts.end(), srcPortIt) << "port ID " << srcPortId;
+ mRoutedPorts.push_back(*srcPortIt);
+ }
+ } else {
+ const auto sinkPortIt = findById(allPorts, r.sinkPortId);
+ ASSERT_NE(allPorts.end(), sinkPortIt) << "port ID " << r.sinkPortId;
+ mRoutedPorts.push_back(*sinkPortIt);
+ }
+ }
+ }
+ void GetProfileSizes() {
+ std::transform(
+ mRoutedPorts.begin(), mRoutedPorts.end(),
+ std::inserter(mPortProfileSizes, mPortProfileSizes.end()),
+ [](const auto& port) { return std::make_pair(port.id, port.profiles.size()); });
+ }
+
+ const int32_t mPortId;
+ std::vector<AudioPort> mRoutedPorts;
+ std::map<int32_t, size_t> mPortProfileSizes;
+};
+
// Note: This test relies on simulation of external device connections by the HAL module.
TEST_P(AudioCoreModule, ExternalDeviceMixPortConfigs) {
// After an external device has been connected, all mix ports that can be routed
// to the device port for the connected device must have non-empty profiles.
+ // Since the test connects and disconnects a single device each time, the size
+ // of profiles for all mix ports routed to the device port under test must get back
+ // to the original count once the external device is disconnected.
ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
if (externalDevicePorts.empty()) {
GTEST_SKIP() << "No external devices in the module.";
}
for (const auto& port : externalDevicePorts) {
- WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
- ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
- std::vector<AudioRoute> routes;
- ASSERT_IS_OK(module->getAudioRoutesForAudioPort(portConnected.getId(), &routes));
- std::vector<AudioPort> allPorts;
- ASSERT_IS_OK(module->getAudioPorts(&allPorts));
- for (const auto& r : routes) {
- if (r.sinkPortId == portConnected.getId()) {
- for (const auto& srcPortId : r.sourcePortIds) {
- const auto srcPortIt = findById(allPorts, srcPortId);
- ASSERT_NE(allPorts.end(), srcPortIt) << "port ID " << srcPortId;
- EXPECT_NE(0UL, srcPortIt->profiles.size())
- << " source port " << srcPortIt->toString() << " must have its profiles"
- << " populated following external device connection";
- }
- } else {
- const auto sinkPortIt = findById(allPorts, r.sinkPortId);
- ASSERT_NE(allPorts.end(), sinkPortIt) << "port ID " << r.sinkPortId;
- EXPECT_NE(0UL, sinkPortIt->profiles.size())
- << " source port " << sinkPortIt->toString() << " must have its"
- << " profiles populated following external device connection";
+ SCOPED_TRACE(port.toString());
+ RoutedPortsProfilesSnapshot before(port.id);
+ ASSERT_NO_FATAL_FAILURE(before.Capture(module.get()));
+ if (before.getRoutedPorts().empty()) continue;
+ {
+ WithDevicePortConnectedState portConnected(GenerateUniqueDeviceAddress(port));
+ ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get(), moduleConfig.get()));
+ RoutedPortsProfilesSnapshot connected(portConnected.getId());
+ ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
+ EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
+ }
+ RoutedPortsProfilesSnapshot after(port.id);
+ ASSERT_NO_FATAL_FAILURE(after.Capture(module.get()));
+ EXPECT_NO_FATAL_FAILURE(after.VerifyNoProfilesChanges(before));
+ }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, TwoExternalDevicesMixPortConfigsNested) {
+ // Ensure that in the case when two external devices are connected to the same
+ // device port, disconnecting one of them does not erase the profiles of routed mix ports.
+ // In this scenario, the connections are "nested."
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
+ if (externalDevicePorts.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : externalDevicePorts) {
+ SCOPED_TRACE(port.toString());
+ WithDevicePortConnectedState portConnected1(GenerateUniqueDeviceAddress(port));
+ ASSERT_NO_FATAL_FAILURE(portConnected1.SetUp(module.get(), moduleConfig.get()));
+ {
+ // Connect and disconnect another device, if possible. It might not be possible
+ // for point-to-point connections, like analog or SPDIF.
+ WithDevicePortConnectedState portConnected2(GenerateUniqueDeviceAddress(port));
+ if (auto status = portConnected2.SetUpNoChecks(module.get(), moduleConfig.get());
+ !status.isOk()) {
+ continue;
}
}
+ RoutedPortsProfilesSnapshot connected(portConnected1.getId());
+ ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
+ EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
+ }
+}
+
+// Note: This test relies on simulation of external device connections by the HAL module.
+TEST_P(AudioCoreModule, TwoExternalDevicesMixPortConfigsInterleaved) {
+ // Ensure that in the case when two external devices are connected to the same
+ // device port, disconnecting one of them does not erase the profiles of routed mix ports.
+ // In this scenario, the connections are "interleaved."
+ ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
+ std::vector<AudioPort> externalDevicePorts = moduleConfig->getExternalDevicePorts();
+ if (externalDevicePorts.empty()) {
+ GTEST_SKIP() << "No external devices in the module.";
+ }
+ for (const auto& port : externalDevicePorts) {
+ SCOPED_TRACE(port.toString());
+ auto portConnected1 =
+ std::make_unique<WithDevicePortConnectedState>(GenerateUniqueDeviceAddress(port));
+ ASSERT_NO_FATAL_FAILURE(portConnected1->SetUp(module.get(), moduleConfig.get()));
+ WithDevicePortConnectedState portConnected2(GenerateUniqueDeviceAddress(port));
+ // Connect another device, if possible. It might not be possible for point-to-point
+ // connections, like analog or SPDIF.
+ if (auto status = portConnected2.SetUpNoChecks(module.get(), moduleConfig.get());
+ !status.isOk()) {
+ continue;
+ }
+ portConnected1.reset();
+ RoutedPortsProfilesSnapshot connected(portConnected2.getId());
+ ASSERT_NO_FATAL_FAILURE(connected.Capture(module.get()));
+ EXPECT_NO_FATAL_FAILURE(connected.VerifyProfilesNonEmpty());
}
}
@@ -1989,7 +2159,13 @@
std::vector<AudioMMapPolicyInfo> policyInfos;
EXPECT_IS_OK(module->getMmapPolicyInfos(mmapPolicyType, &policyInfos))
<< toString(mmapPolicyType);
- EXPECT_EQ(isMmapSupported, !policyInfos.empty());
+ const bool isMMapSupportedByPolicyInfos =
+ std::find_if(policyInfos.begin(), policyInfos.end(), [](const auto& info) {
+ return info.mmapPolicy == AudioMMapPolicy::AUTO ||
+ info.mmapPolicy == AudioMMapPolicy::ALWAYS;
+ }) != policyInfos.end();
+ EXPECT_EQ(isMmapSupported, isMMapSupportedByPolicyInfos)
+ << ::android::internal::ToString(policyInfos);
}
}
@@ -3486,9 +3662,12 @@
patches.push_back(
std::make_unique<WithAudioPatch>(srcSink.first, srcSink.second));
EXPECT_NO_FATAL_FAILURE(patches[patches.size() - 1]->SetUp(module.get()));
+ EXPECT_NO_FATAL_FAILURE(
+ patches[patches.size() - 1]->VerifyAgainstAllPatches(module.get()));
} else {
WithAudioPatch patch(srcSink.first, srcSink.second);
EXPECT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ EXPECT_NO_FATAL_FAILURE(patch.VerifyAgainstAllPatches(module.get()));
}
}
}
@@ -3509,6 +3688,29 @@
}
}
+ void UpdatePatchPorts(bool isInput) {
+ auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
+ if (srcSinkGroups.empty()) {
+ GTEST_SKIP() << "No routes to any attached " << direction(isInput, false) << " devices";
+ }
+ bool hasAtLeastOnePair = false;
+ for (const auto& srcSinkGroup : srcSinkGroups) {
+ const auto& srcSinks = srcSinkGroup.second;
+ if (srcSinks.size() < 2) continue;
+ hasAtLeastOnePair = true;
+ const auto& pair1 = srcSinks[0];
+ const auto& pair2 = srcSinks[1];
+ WithAudioPatch patch(pair1.first, pair1.second);
+ ASSERT_NO_FATAL_FAILURE(patch.SetUp(module.get()));
+ WithAudioPatch update(patch, pair2.first, pair2.second);
+ EXPECT_NO_FATAL_FAILURE(update.SetUp(module.get()));
+ EXPECT_NO_FATAL_FAILURE(update.VerifyAgainstAllPatches(module.get()));
+ }
+ if (!hasAtLeastOnePair) {
+ GTEST_SKIP() << "No routes with multiple sources";
+ }
+ }
+
void UpdateInvalidPatchId(bool isInput) {
auto srcSinkGroups = moduleConfig->getRoutableSrcSinkGroups(isInput);
if (srcSinkGroups.empty()) {
@@ -3548,6 +3750,7 @@
TEST_PATCH_BOTH_DIRECTIONS(SetPatch);
TEST_PATCH_BOTH_DIRECTIONS(UpdateInvalidPatchId);
TEST_PATCH_BOTH_DIRECTIONS(UpdatePatch);
+TEST_PATCH_BOTH_DIRECTIONS(UpdatePatchPorts);
TEST_P(AudioModulePatch, ResetInvalidPatchId) {
std::set<int32_t> patchIds;
@@ -4028,58 +4231,32 @@
class WithRemoteSubmix {
public:
WithRemoteSubmix() = default;
- WithRemoteSubmix(AudioDeviceAddress address) : mAddress(address) {}
+ explicit WithRemoteSubmix(AudioDeviceAddress address) : mAddress(address) {}
WithRemoteSubmix(const WithRemoteSubmix&) = delete;
WithRemoteSubmix& operator=(const WithRemoteSubmix&) = delete;
- std::optional<AudioPort> getAudioPort() {
+ static std::optional<AudioPort> getRemoteSubmixAudioPort(
+ ModuleConfig* moduleConfig,
+ const std::optional<AudioDeviceAddress>& address = std::nullopt) {
AudioDeviceType deviceType = IOTraits<Stream>::is_input ? AudioDeviceType::IN_SUBMIX
: AudioDeviceType::OUT_SUBMIX;
- auto ports = mModuleConfig->getAudioPortsForDeviceTypes(
+ auto ports = moduleConfig->getAudioPortsForDeviceTypes(
std::vector<AudioDeviceType>{deviceType},
AudioDeviceDescription::CONNECTION_VIRTUAL);
- if (!ports.empty()) return ports.front();
- return {};
- }
- /* Connect remote submix external device */
- void SetUpPortConnection() {
- auto port = getAudioPort();
- ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found";
- if (mAddress.has_value()) {
- port.value().ext.template get<AudioPortExt::Tag::device>().device.address =
- mAddress.value();
+ if (ports.empty()) return {};
+ AudioPort port = ports.front();
+ if (address) {
+ port.ext.template get<AudioPortExt::Tag::device>().device.address = address.value();
} else {
- port = GenerateUniqueDeviceAddress(port.value());
+ port = GenerateUniqueDeviceAddress(port);
}
- mConnectedPort = std::make_unique<WithDevicePortConnectedState>(port.value());
- ASSERT_NO_FATAL_FAILURE(mConnectedPort->SetUp(mModule, mModuleConfig));
+ return port;
}
- AudioDeviceAddress getAudioDeviceAddress() {
- if (!mAddress.has_value()) {
- mAddress = mConnectedPort->get()
- .ext.template get<AudioPortExt::Tag::device>()
- .device.address;
- }
- return mAddress.value();
- }
- /* Get mix port config for stream and setup patch for it. */
- void SetupPatch() {
- const auto portConfig =
- mModuleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
- if (!portConfig.has_value()) {
- LOG(DEBUG) << __func__ << ": portConfig not found";
- mSkipTest = true;
- return;
- }
- auto devicePortConfig = mModuleConfig->getSingleConfigForDevicePort(mConnectedPort->get());
- mPatch = std::make_unique<WithAudioPatch>(IOTraits<Stream>::is_input, portConfig.value(),
- devicePortConfig);
- ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(mModule));
- }
- void SetUp(IModule* module, ModuleConfig* moduleConfig) {
+ std::optional<AudioDeviceAddress> getAudioDeviceAddress() const { return mAddress; }
+ void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& connectedPort) {
mModule = module;
mModuleConfig = moduleConfig;
- ASSERT_NO_FATAL_FAILURE(SetUpPortConnection());
- ASSERT_NO_FATAL_FAILURE(SetupPatch());
+
+ ASSERT_NO_FATAL_FAILURE(SetupPatch(connectedPort));
if (!mSkipTest) {
// open stream
mStream = std::make_unique<WithStream<Stream>>(
@@ -4087,6 +4264,11 @@
ASSERT_NO_FATAL_FAILURE(
mStream->SetUp(mModule, AudioCoreModuleBase::kDefaultBufferSizeFrames));
}
+ mAddress = connectedPort.ext.template get<AudioPortExt::Tag::device>().device.address;
+ }
+ void SetUp(IModule* module, ModuleConfig* moduleConfig) {
+ ASSERT_NO_FATAL_FAILURE(SetUpPortConnection(module, moduleConfig));
+ SetUp(module, moduleConfig, mConnectedPort->get());
}
void sendBurstCommands() {
const StreamContext* context = mStream->getContext();
@@ -4104,9 +4286,31 @@
}
EXPECT_FALSE(driver.hasRetrogradeObservablePosition());
}
- bool skipTest() { return mSkipTest; }
+ bool skipTest() const { return mSkipTest; }
private:
+ /* Connect remote submix external device */
+ void SetUpPortConnection(IModule* module, ModuleConfig* moduleConfig) {
+ auto port = getRemoteSubmixAudioPort(moduleConfig, mAddress);
+ ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found";
+ mConnectedPort = std::make_unique<WithDevicePortConnectedState>(port.value());
+ ASSERT_NO_FATAL_FAILURE(mConnectedPort->SetUp(module, moduleConfig));
+ }
+ /* Get mix port config for stream and setup patch for it. */
+ void SetupPatch(const AudioPort& connectedPort) {
+ const auto portConfig =
+ mModuleConfig->getSingleConfigForMixPort(IOTraits<Stream>::is_input);
+ if (!portConfig.has_value()) {
+ LOG(DEBUG) << __func__ << ": portConfig not found";
+ mSkipTest = true;
+ return;
+ }
+ auto devicePortConfig = mModuleConfig->getSingleConfigForDevicePort(connectedPort);
+ mPatch = std::make_unique<WithAudioPatch>(IOTraits<Stream>::is_input, portConfig.value(),
+ devicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(mModule));
+ }
+
bool mSkipTest = false;
IModule* mModule = nullptr;
ModuleConfig* mModuleConfig = nullptr;
@@ -4144,9 +4348,11 @@
if (streamOut.skipTest()) {
GTEST_SKIP() << "No mix port for attached devices";
}
+ auto address = streamOut.getAudioDeviceAddress();
+ ASSERT_TRUE(address.has_value());
// open input stream
- WithRemoteSubmix<IStreamIn> streamIn(streamOut.getAudioDeviceAddress());
+ WithRemoteSubmix<IStreamIn> streamIn(address.value());
ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
if (streamIn.skipTest()) {
GTEST_SKIP() << "No mix port for attached devices";
@@ -4163,9 +4369,11 @@
if (streamOut.skipTest()) {
GTEST_SKIP() << "No mix port for attached devices";
}
+ auto address = streamOut.getAudioDeviceAddress();
+ ASSERT_TRUE(address.has_value());
// open input stream
- WithRemoteSubmix<IStreamIn> streamIn(streamOut.getAudioDeviceAddress());
+ WithRemoteSubmix<IStreamIn> streamIn(address.value());
ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
if (streamIn.skipTest()) {
GTEST_SKIP() << "No mix port for attached devices";
@@ -4177,6 +4385,43 @@
ASSERT_NO_FATAL_FAILURE(streamIn.sendBurstCommands());
}
+TEST_P(AudioModuleRemoteSubmix, OpenInputMultipleTimes) {
+ // open output stream
+ WithRemoteSubmix<IStreamOut> streamOut;
+ ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
+ if (streamOut.skipTest()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ auto address = streamOut.getAudioDeviceAddress();
+ ASSERT_TRUE(address.has_value());
+
+ // connect remote submix input device port
+ auto port = WithRemoteSubmix<IStreamIn>::getRemoteSubmixAudioPort(moduleConfig.get(),
+ address.value());
+ ASSERT_TRUE(port.has_value()) << "Device AudioPort for remote submix not found";
+ WithDevicePortConnectedState connectedInputPort(port.value());
+ ASSERT_NO_FATAL_FAILURE(connectedInputPort.SetUp(module.get(), moduleConfig.get()));
+
+ // open input streams
+ const int streamInCount = 3;
+ std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(streamInCount);
+ for (int i = 0; i < streamInCount; i++) {
+ streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>();
+ ASSERT_NO_FATAL_FAILURE(
+ streamIns[i]->SetUp(module.get(), moduleConfig.get(), connectedInputPort.get()));
+ if (streamIns[i]->skipTest()) {
+ GTEST_SKIP() << "No mix port for attached devices";
+ }
+ }
+ // write something to output stream
+ ASSERT_NO_FATAL_FAILURE(streamOut.sendBurstCommands());
+
+ // read from input streams
+ for (int i = 0; i < streamInCount; i++) {
+ ASSERT_NO_FATAL_FAILURE(streamIns[i]->sendBurstCommands());
+ }
+}
+
INSTANTIATE_TEST_SUITE_P(AudioModuleRemoteSubmixTest, AudioModuleRemoteSubmix,
::testing::ValuesIn(getRemoteSubmixModuleInstance()));
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioModuleRemoteSubmix);
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 3011a5e..1876756 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -42,11 +42,11 @@
using aidl::android::hardware::audio::effect::CommandId;
using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::Flags;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::IFactory;
using aidl::android::hardware::audio::effect::Parameter;
using aidl::android::hardware::audio::effect::State;
-using aidl::android::hardware::audio::effect::Flags;
using aidl::android::media::audio::common::AudioDeviceDescription;
using aidl::android::media::audio::common::AudioDeviceType;
using aidl::android::media::audio::common::AudioMode;
@@ -87,11 +87,11 @@
};
class AudioEffectDataPathTest : public AudioEffectTest {
- public:
- void SetUp() override {
- AudioEffectTest::SetUp();
- SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
- }
+ public:
+ void SetUp() override {
+ AudioEffectTest::SetUp();
+ SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+ }
};
TEST_P(AudioEffectTest, SetupAndTearDown) {
@@ -504,6 +504,11 @@
// Set and get AudioDeviceDescription in Parameter
TEST_P(AudioEffectTest, SetAndGetParameterDeviceDescription) {
+ if (!mDescriptor.common.flags.deviceIndication) {
+ GTEST_SKIP() << "Skipping test as effect does not support deviceIndication"
+ << mDescriptor.common.flags.toString();
+ }
+
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
ASSERT_NO_FATAL_FAILURE(open(mEffect));
@@ -527,6 +532,11 @@
// Set and get AudioMode in Parameter
TEST_P(AudioEffectTest, SetAndGetParameterAudioMode) {
+ if (!mDescriptor.common.flags.audioModeIndication) {
+ GTEST_SKIP() << "Skipping test as effect does not support audioModeIndication"
+ << mDescriptor.common.flags.toString();
+ }
+
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
ASSERT_NO_FATAL_FAILURE(open(mEffect));
@@ -547,6 +557,11 @@
// Set and get AudioSource in Parameter
TEST_P(AudioEffectTest, SetAndGetParameterAudioSource) {
+ if (!mDescriptor.common.flags.audioSourceIndication) {
+ GTEST_SKIP() << "Skipping test as effect does not support audioSourceIndication"
+ << mDescriptor.common.flags.toString();
+ }
+
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
ASSERT_NO_FATAL_FAILURE(open(mEffect));
@@ -567,6 +582,11 @@
// Set and get VolumeStereo in Parameter
TEST_P(AudioEffectTest, SetAndGetParameterVolume) {
+ if (mDescriptor.common.flags.volume == Flags::Volume::NONE) {
+ GTEST_SKIP() << "Skipping test as effect does not support volume"
+ << mDescriptor.common.flags.toString();
+ }
+
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
ASSERT_NO_FATAL_FAILURE(open(mEffect));
diff --git a/audio/core/all-versions/default/PrimaryDevice.cpp b/audio/core/all-versions/default/PrimaryDevice.cpp
index cf162f1..13efbbc 100644
--- a/audio/core/all-versions/default/PrimaryDevice.cpp
+++ b/audio/core/all-versions/default/PrimaryDevice.cpp
@@ -283,7 +283,7 @@
_hidl_cb(retval, TtyMode::OFF);
return Void();
}
- TtyMode mode = convertTtyModeToHIDL(halMode);
+ TtyMode mode = convertTtyModeToHIDL(halMode.c_str());
if (mode == TtyMode(-1)) {
ALOGE("HAL returned invalid TTY value: %s", halMode.c_str());
_hidl_cb(Result::INVALID_STATE, TtyMode::OFF);
diff --git a/automotive/can/1.0/default/libc++fs/include/automotive/filesystem b/automotive/can/1.0/default/libc++fs/include/automotive/filesystem
index 660ad09..bd3dda5 100644
--- a/automotive/can/1.0/default/libc++fs/include/automotive/filesystem
+++ b/automotive/can/1.0/default/libc++fs/include/automotive/filesystem
@@ -9,6 +9,18 @@
//===----------------------------------------------------------------------===//
#ifndef _LIBAUTO_FILESYSTEM
#define _LIBAUTO_FILESYSTEM
+
+// TODO(152067309): Remove this once the libc++ upgrade is complete.
+#include <__config>
+#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION > 8000
+
+#include <filesystem>
+namespace android::hardware::automotive {
+namespace filesystem = std::filesystem;
+}
+
+#else
+
/*
filesystem synopsis
@@ -2696,4 +2708,6 @@
_LIBCPP_POP_MACROS
+#endif // defined(_LIBCPP_VERSION) && _LIBCPP_VERSION > 8000
+
#endif // _LIBAUTO_FILESYSTEM
diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp b/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp
index 37c863b..0dbf492 100644
--- a/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp
+++ b/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp
@@ -6,9 +6,15 @@
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+
+// TODO(152067309): Remove this once the libc++ upgrade is complete.
+#include <__config>
+#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
+
/* clang-format off */
#include "automotive/filesystem"
#include <__config>
+
#if defined(_LIBCPP_WIN32API)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
@@ -395,3 +401,5 @@
} // namespace android::hardware::automotive::filesystem
/* clang-format on */
+
+#endif // defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp b/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp
index 404c0bd..6a76bdc 100644
--- a/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp
+++ b/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp
@@ -6,6 +6,11 @@
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+
+// TODO(152067309): Remove this once the libc++ upgrade is complete.
+#include <__config>
+#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
+
/* clang-format off */
#include "automotive/filesystem"
#include <array>
@@ -1771,3 +1776,5 @@
#endif
} // namespace android::hardware::automotive::filesystem
/* clang-format on */
+
+#endif // defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
diff --git a/automotive/evs/aidl/impl/default/Android.bp b/automotive/evs/aidl/impl/default/Android.bp
index 79ee956..6b638a3 100644
--- a/automotive/evs/aidl/impl/default/Android.bp
+++ b/automotive/evs/aidl/impl/default/Android.bp
@@ -21,45 +21,41 @@
default_applicable_licenses: ["hardware_interfaces_license"],
}
-cc_binary {
- name: "android.hardware.automotive.evs-aidl-default-service",
+cc_defaults {
+ name: "android.hardware.automotive.evs-aidl-default-service-default",
defaults: ["EvsHalDefaults"],
- vintf_fragments: ["manifest_evs-default-service.xml"],
- init_rc: ["evs-default-service.rc"],
- vendor: true,
- relative_install_path: "hw",
- cflags: [
- "-DGL_GLEXT_PROTOTYPES",
- "-DEGL_EGLEXT_PROTOTYPES",
- "-Wall",
- "-Wextra",
- "-Werror",
- "-Wthread-safety",
- ],
- srcs: [
- ":libgui_frame_event_aidl",
- "src/*.cpp",
- ],
shared_libs: [
"android.hardware.graphics.bufferqueue@1.0",
"android.hardware.graphics.bufferqueue@2.0",
"android.hidl.token@1.0-utils",
"libEGL",
"libGLESv2",
- "libbase",
"libbinder_ndk",
"libbufferqueueconverter",
"libcamera_metadata",
"libhardware_legacy",
"libhidlbase",
- "liblog",
"libnativewindow",
"libtinyxml2",
"libui",
- "libutils",
"libyuv",
],
- static_libs: [
+}
+
+cc_library {
+ name: "android.hardware.automotive.evs-aidl-default-service-lib",
+ defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
+ vendor: true,
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+ ],
+ srcs: [
+ ":libgui_frame_event_aidl",
+ "src/*.cpp",
+ ],
+ exclude_srcs: ["src/service.cpp"],
+ whole_static_libs: [
"android.frameworks.automotive.display-V2-ndk",
"android.hardware.automotive.evs-V2-ndk",
"android.hardware.common-V2-ndk",
@@ -71,6 +67,25 @@
],
local_include_dirs: ["include"],
include_dirs: ["frameworks/native/include/"],
+ export_include_dirs: ["include"],
+}
+
+cc_binary {
+ name: "android.hardware.automotive.evs-aidl-default-service",
+ defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
+ vintf_fragments: ["manifest_evs-default-service.xml"],
+ init_rc: ["evs-default-service.rc"],
+ vendor: true,
+ relative_install_path: "hw",
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+ ],
+ srcs: ["src/service.cpp"],
+ static_libs: [
+ "android.hardware.automotive.evs-aidl-default-service-lib",
+ ],
+ include_dirs: ["frameworks/native/include/"],
required: ["evs_mock_hal_configuration.xml"],
}
@@ -80,3 +95,31 @@
src: "resources/evs_mock_configuration.xml",
sub_dir: "automotive/evs",
}
+
+cc_test {
+ name: "android.hardware.automotive.evs-aidl-default-service_cam_buffer_test",
+ defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
+ vendor: true,
+ srcs: ["tests/EvsCameraBufferTest.cpp"],
+ static_libs: [
+ "android.hardware.automotive.evs-aidl-default-service-lib",
+ "libgmock",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+}
+
+cc_test {
+ name: "android.hardware.automotive.evs-aidl-default-service_cam_state_test",
+ defaults: ["android.hardware.automotive.evs-aidl-default-service-default"],
+ vendor: true,
+ srcs: ["tests/EvsCameraStateTest.cpp"],
+ static_libs: [
+ "android.hardware.automotive.evs-aidl-default-service-lib",
+ "libgmock",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+}
diff --git a/automotive/evs/aidl/impl/default/include/ConfigManager.h b/automotive/evs/aidl/impl/default/include/ConfigManager.h
index 1d5fe77..37a17dc 100644
--- a/automotive/evs/aidl/impl/default/include/ConfigManager.h
+++ b/automotive/evs/aidl/impl/default/include/ConfigManager.h
@@ -25,8 +25,10 @@
#include <tinyxml2.h>
+#include <limits>
#include <string>
#include <string_view>
+#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@@ -54,6 +56,15 @@
/* Camera device's capabilities and metadata */
class CameraInfo {
public:
+ enum class DeviceType : std::int32_t {
+ NONE = 0,
+ MOCK = 1,
+ V4L2 = 2,
+ VIDEO = 3,
+
+ UNKNOWN = std::numeric_limits<std::underlying_type_t<DeviceType>>::max(),
+ };
+
CameraInfo() : characteristics(nullptr) {}
virtual ~CameraInfo();
@@ -69,6 +80,10 @@
return characteristics != nullptr;
}
+ static DeviceType deviceTypeFromSV(const std::string_view sv);
+
+ DeviceType deviceType{DeviceType::NONE};
+
/*
* List of supported controls that the primary client can program.
* Paraemters are stored with its valid range
diff --git a/automotive/evs/aidl/impl/default/include/EvsAllCameras.h b/automotive/evs/aidl/impl/default/include/EvsAllCameras.h
new file mode 100644
index 0000000..a76501d
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/EvsAllCameras.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EvsMockCamera.h"
+#include "EvsVideoEmulatedCamera.h"
diff --git a/automotive/evs/aidl/impl/default/include/EvsCamera.h b/automotive/evs/aidl/impl/default/include/EvsCamera.h
new file mode 100644
index 0000000..539d5f6
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/EvsCamera.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EvsCameraBase.h"
+
+#include <aidl/android/hardware/automotive/evs/IEvsCameraStream.h>
+#include <cutils/native_handle.h>
+
+#include <cstddef>
+#include <mutex>
+#include <utility>
+#include <vector>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class EvsCamera : public EvsCameraBase {
+ private:
+ using Base = EvsCameraBase;
+ using Self = EvsCamera;
+
+ public:
+ using Base::Base;
+
+ ~EvsCamera() override;
+
+ // Methods from ::android::hardware::automotive::evs::IEvsCamera follow.
+ ndk::ScopedAStatus doneWithFrame(const std::vector<evs::BufferDesc>& buffers) override;
+
+ ndk::ScopedAStatus importExternalBuffers(const std::vector<evs::BufferDesc>& buffers,
+ int32_t* _aidl_return) override;
+
+ ndk::ScopedAStatus setMaxFramesInFlight(int32_t bufferCount) override;
+
+ ndk::ScopedAStatus startVideoStream(
+ const std::shared_ptr<evs::IEvsCameraStream>& receiver) override;
+
+ ndk::ScopedAStatus stopVideoStream() override;
+
+ ndk::ScopedAStatus pauseVideoStream() override;
+
+ ndk::ScopedAStatus resumeVideoStream() override;
+
+ protected:
+ virtual ::android::status_t allocateOneFrame(buffer_handle_t* handle) = 0;
+
+ virtual void freeOneFrame(const buffer_handle_t handle);
+
+ virtual bool preVideoStreamStart_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+ ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck);
+
+ virtual bool startVideoStreamImpl_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+ ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) = 0;
+
+ virtual bool postVideoStreamStart_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+ ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck);
+
+ virtual bool preVideoStreamStop_locked(ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck);
+
+ virtual bool stopVideoStreamImpl_locked(ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) = 0;
+
+ virtual bool postVideoStreamStop_locked(ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck);
+
+ void shutdown() override;
+
+ void closeAllBuffers_unsafe();
+
+ // Returns (ID, handle) if succeeds. (kInvalidBufferID, nullptr) otherwise.
+ [[nodiscard]] std::pair<std::size_t, buffer_handle_t> useBuffer_unsafe();
+
+ void returnBuffer_unsafe(const std::size_t id);
+
+ bool increaseAvailableFrames_unsafe(const buffer_handle_t handle);
+
+ bool decreaseAvailableFrames_unsafe();
+
+ bool setAvailableFrames_unsafe(const std::size_t bufferCount);
+
+ void swapBufferFrames_unsafe(const std::size_t pos1, const std::size_t pos2);
+
+ struct BufferRecord {
+ BufferRecord() = default;
+ BufferRecord(const BufferRecord&) = default;
+ BufferRecord(BufferRecord&&) = default;
+ BufferRecord& operator=(const BufferRecord&) = default;
+ BufferRecord& operator=(BufferRecord&&) = default;
+ ~BufferRecord() = default;
+
+ explicit BufferRecord(buffer_handle_t h) : handle(h) {}
+
+ buffer_handle_t handle{nullptr};
+ bool inUse{false};
+ };
+
+ enum class StreamState {
+ STOPPED = 0,
+ RUNNING = 1,
+ STOPPING = 2,
+ DEAD = 3,
+ };
+
+ StreamState mStreamState{StreamState::STOPPED};
+
+ std::mutex mMutex;
+
+ // Graphics buffers to transfer images, always in the order of:
+ // In use buffers ... available buffers ... unavailable (unallocated) buffers.
+ std::vector<BufferRecord> mBuffers;
+
+ // Double-mapping between buffer position and ID.
+ std::vector<std::size_t> mBufferPosToId;
+ std::vector<std::size_t> mBufferIdToPos;
+
+ std::size_t mAvailableFrames{0};
+ std::size_t mFramesInUse{0};
+
+ // We use all 1's as a reserved invalid buffer ID.
+ static constexpr std::size_t kInvalidBufferID = ~static_cast<std::size_t>(0);
+
+ public:
+ static bool IsBufferIDValid(const std::size_t bufferId) { return ~bufferId; }
+};
+
+} // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/include/EvsCameraBase.h b/automotive/evs/aidl/impl/default/include/EvsCameraBase.h
new file mode 100644
index 0000000..c3e9dfc
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/EvsCameraBase.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/automotive/evs/BnEvsCamera.h>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class EvsCameraBase : public evs::BnEvsCamera {
+ private:
+ using Base = evs::BnEvsCamera;
+ using Self = EvsCameraBase;
+
+ public:
+ using Base::Base;
+
+ ~EvsCameraBase() override = default;
+
+ virtual void shutdown() = 0;
+
+ protected:
+ // This is used for the derived classes and it prevents constructors from direct access
+ // while it allows this class to be instantiated via ndk::SharedRefBase::make<>.
+ struct Sigil {
+ explicit Sigil() = default;
+ };
+};
+
+} // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/include/EvsEnumerator.h b/automotive/evs/aidl/impl/default/include/EvsEnumerator.h
index 3897b4e..9dcc774 100644
--- a/automotive/evs/aidl/impl/default/include/EvsEnumerator.h
+++ b/automotive/evs/aidl/impl/default/include/EvsEnumerator.h
@@ -17,8 +17,8 @@
#pragma once
#include "ConfigManager.h"
+#include "EvsCameraBase.h"
#include "EvsGlDisplay.h"
-#include "EvsMockCamera.h"
#include <aidl/android/frameworks/automotive/display/ICarDisplayProxy.h>
#include <aidl/android/hardware/automotive/evs/BnEvsEnumerator.h>
@@ -73,7 +73,7 @@
private:
struct CameraRecord {
evs::CameraDesc desc;
- std::weak_ptr<EvsMockCamera> activeInstance;
+ std::weak_ptr<EvsCameraBase> activeInstance;
CameraRecord(const char* cameraId) : desc() { desc.id = cameraId; }
};
diff --git a/automotive/evs/aidl/impl/default/include/EvsMockCamera.h b/automotive/evs/aidl/impl/default/include/EvsMockCamera.h
index 7e010a2..cd68532 100644
--- a/automotive/evs/aidl/impl/default/include/EvsMockCamera.h
+++ b/automotive/evs/aidl/impl/default/include/EvsMockCamera.h
@@ -17,36 +17,36 @@
#pragma once
#include "ConfigManager.h"
+#include "EvsCamera.h"
-#include <aidl/android/hardware/automotive/evs/BnEvsCamera.h>
-#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
#include <aidl/android/hardware/automotive/evs/CameraDesc.h>
#include <aidl/android/hardware/automotive/evs/CameraParam.h>
-#include <aidl/android/hardware/automotive/evs/EvsResult.h>
#include <aidl/android/hardware/automotive/evs/IEvsCameraStream.h>
#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
#include <aidl/android/hardware/automotive/evs/ParameterRange.h>
#include <aidl/android/hardware/automotive/evs/Stream.h>
-// #include <android-base/result.h>
#include <android/hardware_buffer.h>
#include <ui/GraphicBuffer.h>
-#include <functional>
+#include <cstdint>
+#include <memory>
#include <thread>
+#include <unordered_map>
+#include <vector>
namespace aidl::android::hardware::automotive::evs::implementation {
-class EvsMockCamera : public evs::BnEvsCamera {
- // This prevents constructors from direct access while it allows this class to
- // be instantiated via ndk::SharedRefBase::make<>.
+class EvsMockCamera : public EvsCamera {
private:
- struct Sigil {
- explicit Sigil() = default;
- };
+ using Base = EvsCamera;
public:
+ EvsMockCamera(Sigil sigil, const char* deviceName,
+ std::unique_ptr<ConfigManager::CameraInfo>& camInfo);
+ EvsMockCamera(const EvsMockCamera&) = delete;
+ EvsMockCamera& operator=(const EvsMockCamera&) = delete;
+
// Methods from ::android::hardware::automotive::evs::IEvsCamera follow.
- ndk::ScopedAStatus doneWithFrame(const std::vector<evs::BufferDesc>& buffers) override;
ndk::ScopedAStatus forcePrimaryClient(
const std::shared_ptr<evs::IEvsDisplay>& display) override;
ndk::ScopedAStatus getCameraInfo(evs::CameraDesc* _aidl_return) override;
@@ -58,47 +58,37 @@
ndk::ScopedAStatus getParameterList(std::vector<evs::CameraParam>* _aidl_return) override;
ndk::ScopedAStatus getPhysicalCameraInfo(const std::string& deviceId,
evs::CameraDesc* _aidl_return) override;
- ndk::ScopedAStatus importExternalBuffers(const std::vector<evs::BufferDesc>& buffers,
- int32_t* _aidl_return) override;
- ndk::ScopedAStatus pauseVideoStream() override;
- ndk::ScopedAStatus resumeVideoStream() override;
ndk::ScopedAStatus setExtendedInfo(int32_t opaqueIdentifier,
const std::vector<uint8_t>& opaqueValue) override;
ndk::ScopedAStatus setIntParameter(evs::CameraParam id, int32_t value,
std::vector<int32_t>* effectiveValue) override;
ndk::ScopedAStatus setPrimaryClient() override;
- ndk::ScopedAStatus setMaxFramesInFlight(int32_t bufferCount) override;
- ndk::ScopedAStatus startVideoStream(
- const std::shared_ptr<evs::IEvsCameraStream>& receiver) override;
- ndk::ScopedAStatus stopVideoStream() override;
ndk::ScopedAStatus unsetPrimaryClient() override;
+ const evs::CameraDesc& getDesc() { return mDescription; }
+
static std::shared_ptr<EvsMockCamera> Create(const char* deviceName);
static std::shared_ptr<EvsMockCamera> Create(
const char* deviceName, std::unique_ptr<ConfigManager::CameraInfo>& camInfo,
const evs::Stream* streamCfg = nullptr);
- EvsMockCamera(const EvsMockCamera&) = delete;
- EvsMockCamera& operator=(const EvsMockCamera&) = delete;
-
- virtual ~EvsMockCamera() override;
- void shutdown();
-
- const evs::CameraDesc& getDesc() { return mDescription; }
-
- // Constructors
- EvsMockCamera(Sigil sigil, const char* deviceName,
- std::unique_ptr<ConfigManager::CameraInfo>& camInfo);
private:
- // These three functions are expected to be called while mAccessLock is held
- bool setAvailableFrames_Locked(unsigned bufferCount);
- unsigned increaseAvailableFrames_Locked(unsigned numToAdd);
- unsigned decreaseAvailableFrames_Locked(unsigned numToRemove);
-
void generateFrames();
void fillMockFrame(buffer_handle_t handle, const AHardwareBuffer_Desc* pDesc);
- void returnBufferLocked(const uint32_t bufferId);
- ndk::ScopedAStatus stopVideoStream_impl();
+
+ ::android::status_t allocateOneFrame(buffer_handle_t* handle) override;
+
+ bool startVideoStreamImpl_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+ ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) override;
+
+ bool stopVideoStreamImpl_locked(ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) override;
+
+ bool postVideoStreamStop_locked(ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) override;
+
+ void initializeParameters();
CameraDesc mDescription = {}; // The properties of this camera
@@ -119,28 +109,6 @@
// Bytes per line in the buffers
uint32_t mStride = 0;
- struct BufferRecord {
- buffer_handle_t handle;
- bool inUse;
-
- explicit BufferRecord(buffer_handle_t h) : handle(h), inUse(false){};
- };
-
- std::vector<BufferRecord> mBuffers; // Graphics buffers to transfer images
- unsigned mFramesAllowed; // How many buffers are we currently using
- unsigned mFramesInUse; // How many buffers are currently outstanding
-
- enum StreamStateValues {
- STOPPED,
- RUNNING,
- STOPPING,
- DEAD,
- };
- StreamStateValues mStreamState;
-
- // Synchronization necessary to deconflict mCaptureThread from the main service thread
- std::mutex mAccessLock;
-
// Static camera module information
std::unique_ptr<ConfigManager::CameraInfo>& mCameraInfo;
@@ -160,7 +128,6 @@
int32_t value;
};
std::unordered_map<CameraParam, std::shared_ptr<CameraParameterDesc>> mParams;
- void initializeParameters();
};
} // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/include/EvsVideoEmulatedCamera.h b/automotive/evs/aidl/impl/default/include/EvsVideoEmulatedCamera.h
new file mode 100644
index 0000000..356a42a
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/EvsVideoEmulatedCamera.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConfigManager.h"
+#include "EvsCamera.h"
+
+#include <aidl/android/hardware/automotive/evs/BufferDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraDesc.h>
+#include <aidl/android/hardware/automotive/evs/CameraParam.h>
+#include <aidl/android/hardware/automotive/evs/IEvsCameraStream.h>
+#include <aidl/android/hardware/automotive/evs/IEvsDisplay.h>
+#include <aidl/android/hardware/automotive/evs/ParameterRange.h>
+#include <aidl/android/hardware/automotive/evs/Stream.h>
+
+#include <cstdint>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class EvsVideoEmulatedCamera : public EvsCamera {
+ public:
+ EvsVideoEmulatedCamera(Sigil sigil, const char* deviceName,
+ std::unique_ptr<ConfigManager::CameraInfo>& camInfo);
+
+ ~EvsVideoEmulatedCamera() override;
+
+ // Methods from ::android::hardware::automotive::evs::IEvsCamera follow.
+ ndk::ScopedAStatus forcePrimaryClient(
+ const std::shared_ptr<evs::IEvsDisplay>& display) override;
+ ndk::ScopedAStatus getCameraInfo(evs::CameraDesc* _aidl_return) override;
+ ndk::ScopedAStatus getExtendedInfo(int32_t opaqueIdentifier,
+ std::vector<uint8_t>* value) override;
+ ndk::ScopedAStatus getIntParameter(evs::CameraParam id, std::vector<int32_t>* value) override;
+ ndk::ScopedAStatus getIntParameterRange(evs::CameraParam id,
+ evs::ParameterRange* _aidl_return) override;
+ ndk::ScopedAStatus getParameterList(std::vector<evs::CameraParam>* _aidl_return) override;
+ ndk::ScopedAStatus getPhysicalCameraInfo(const std::string& deviceId,
+ evs::CameraDesc* _aidl_return) override;
+ ndk::ScopedAStatus setExtendedInfo(int32_t opaqueIdentifier,
+ const std::vector<uint8_t>& opaqueValue) override;
+ ndk::ScopedAStatus setIntParameter(evs::CameraParam id, int32_t value,
+ std::vector<int32_t>* effectiveValue) override;
+ ndk::ScopedAStatus setPrimaryClient() override;
+ ndk::ScopedAStatus unsetPrimaryClient() override;
+
+ const evs::CameraDesc& getDesc() { return mDescription; }
+
+ static std::shared_ptr<EvsVideoEmulatedCamera> Create(const char* deviceName);
+ static std::shared_ptr<EvsVideoEmulatedCamera> Create(
+ const char* deviceName, std::unique_ptr<ConfigManager::CameraInfo>& camInfo,
+ const evs::Stream* streamCfg = nullptr);
+
+ private:
+ // For the camera parameters.
+ struct CameraParameterDesc {
+ CameraParameterDesc(int min = 0, int max = 0, int step = 0, int value = 0) {
+ this->range.min = min;
+ this->range.max = max;
+ this->range.step = step;
+ this->value = value;
+ }
+
+ ParameterRange range;
+ int32_t value;
+ };
+
+ void initializeParameters();
+
+ ::android::status_t allocateOneFrame(buffer_handle_t* handle) override;
+
+ bool startVideoStreamImpl_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+ ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) override;
+
+ bool stopVideoStreamImpl_locked(ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) override;
+
+ // The properties of this camera.
+ CameraDesc mDescription = {};
+
+ // Camera parameters.
+ std::unordered_map<CameraParam, std::shared_ptr<CameraParameterDesc>> mParams;
+
+ // Static camera module information
+ std::unique_ptr<ConfigManager::CameraInfo>& mCameraInfo;
+
+ // For the extended info
+ std::unordered_map<uint32_t, std::vector<uint8_t>> mExtInfo;
+};
+
+} // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/src/ConfigManager.cpp b/automotive/evs/aidl/impl/default/src/ConfigManager.cpp
index da791ed..ba4cdc0 100644
--- a/automotive/evs/aidl/impl/default/src/ConfigManager.cpp
+++ b/automotive/evs/aidl/impl/default/src/ConfigManager.cpp
@@ -40,6 +40,18 @@
std::string_view ConfigManager::sConfigOverridePath =
"/vendor/etc/automotive/evs/evs_configuration_override.xml";
+ConfigManager::CameraInfo::DeviceType ConfigManager::CameraInfo::deviceTypeFromSV(
+ const std::string_view sv) {
+ using namespace std::string_view_literals;
+ static const std::unordered_map<std::string_view, DeviceType> nameToType = {
+ {"mock"sv, DeviceType::MOCK},
+ {"v4l2"sv, DeviceType::V4L2},
+ {"video"sv, DeviceType::VIDEO},
+ };
+ const auto search = nameToType.find(sv);
+ return search == nameToType.end() ? DeviceType::UNKNOWN : search->second;
+}
+
void ConfigManager::printElementNames(const XMLElement* rootElem, const std::string& prefix) const {
const XMLElement* curElem = rootElem;
@@ -128,6 +140,10 @@
return false;
}
+ if (const auto typeAttr = aDeviceElem->FindAttribute("type")) {
+ aCamera->deviceType = CameraInfo::deviceTypeFromSV(typeAttr->Value());
+ }
+
/* size information to allocate camera_metadata_t */
size_t totalEntries = 0;
size_t totalDataSize = 0;
diff --git a/automotive/evs/aidl/impl/default/src/EvsCamera.cpp b/automotive/evs/aidl/impl/default/src/EvsCamera.cpp
new file mode 100644
index 0000000..bc3bfdd
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/src/EvsCamera.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EvsCamera.h"
+
+#include <aidl/android/hardware/automotive/evs/EvsResult.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
+#include <android/hardware_buffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/GraphicBufferMapper.h>
+
+#include <cstddef>
+#include <mutex>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+// Arbitrary limit on number of graphics buffers allowed to be allocated
+// Safeguards against unreasonable resource consumption and provides a testable limit
+constexpr std::size_t kMaxBuffersInFlight = 100;
+
+// Minimum number of buffers to run a video stream
+constexpr int kMinimumBuffersInFlight = 1;
+
+EvsCamera::~EvsCamera() {
+ shutdown();
+}
+
+ndk::ScopedAStatus EvsCamera::doneWithFrame(const std::vector<evs::BufferDesc>& buffers) {
+ std::lock_guard lck(mMutex);
+ for (const auto& desc : buffers) {
+ returnBuffer_unsafe(desc.bufferId);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsCamera::importExternalBuffers(const std::vector<evs::BufferDesc>& buffers,
+ int32_t* _aidl_return) {
+ if (buffers.empty()) {
+ LOG(DEBUG) << __func__
+ << ": Ignoring a request to import external buffers with an empty list.";
+ return ndk::ScopedAStatus::ok();
+ }
+ static auto& mapper = ::android::GraphicBufferMapper::get();
+ std::lock_guard lck(mMutex);
+ std::size_t numBuffersToAdd = std::min(buffers.size(), kMaxBuffersInFlight - mAvailableFrames);
+ if (numBuffersToAdd == 0) {
+ LOG(WARNING) << __func__ << ": The number of buffers has hit the upper limit ("
+ << kMaxBuffersInFlight << "). Stop importing.";
+ return ndk::ScopedAStatus::ok();
+ } else if (numBuffersToAdd < buffers.size()) {
+ LOG(WARNING) << "Exceeds the limit on the number of buffers. Only " << numBuffersToAdd
+ << " buffers will be imported. " << buffers.size() << " are asked.";
+ }
+ const size_t before = mAvailableFrames;
+ for (std::size_t idx = 0; idx < numBuffersToAdd; ++idx) {
+ auto& buffer = buffers[idx];
+ const AHardwareBuffer_Desc* pDesc =
+ reinterpret_cast<const AHardwareBuffer_Desc*>(&buffer.buffer.description);
+
+ buffer_handle_t handleToImport = ::android::dupFromAidl(buffer.buffer.handle);
+ buffer_handle_t handleToStore = nullptr;
+ if (handleToImport == nullptr) {
+ LOG(WARNING) << "Failed to duplicate a memory handle. Ignoring a buffer "
+ << buffer.bufferId;
+ continue;
+ }
+
+ ::android::status_t result =
+ mapper.importBuffer(handleToImport, pDesc->width, pDesc->height, pDesc->layers,
+ pDesc->format, pDesc->usage, pDesc->stride, &handleToStore);
+ if (result != ::android::NO_ERROR || handleToStore == nullptr ||
+ !increaseAvailableFrames_unsafe(handleToStore)) {
+ LOG(WARNING) << "Failed to import a buffer " << buffer.bufferId;
+ }
+ }
+ *_aidl_return = mAvailableFrames - before;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsCamera::setMaxFramesInFlight(int32_t bufferCount) {
+ std::lock_guard lock(mMutex);
+ if (bufferCount < 1) {
+ LOG(ERROR) << "Ignoring setMaxFramesInFlight with less than one buffer requested.";
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::INVALID_ARG));
+ }
+ if (!setAvailableFrames_unsafe(bufferCount)) {
+ LOG(ERROR) << "Failed to adjust the maximum number of frames in flight.";
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+void EvsCamera::freeOneFrame(const buffer_handle_t handle) {
+ static auto& alloc = ::android::GraphicBufferAllocator::get();
+ alloc.free(handle);
+}
+
+bool EvsCamera::preVideoStreamStart_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+ ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& /* lck */) {
+ if (!receiver) {
+ LOG(ERROR) << __func__ << ": Null receiver.";
+ status = ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::INVALID_ARG));
+ return false;
+ }
+
+ // If we've been displaced by another owner of the camera, then we can't do anything else
+ if (mStreamState == StreamState::DEAD) {
+ LOG(ERROR) << __func__ << ": Ignoring when camera has been lost.";
+ status = ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::OWNERSHIP_LOST));
+ return false;
+ }
+
+ if (mStreamState != StreamState::STOPPED) {
+ LOG(ERROR) << __func__ << ": Ignoring when a stream is already running.";
+ status = ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::STREAM_ALREADY_RUNNING));
+ return false;
+ }
+
+ // If the client never indicated otherwise, configure ourselves for a single streaming buffer
+ if (mAvailableFrames < kMinimumBuffersInFlight &&
+ !setAvailableFrames_unsafe(kMinimumBuffersInFlight)) {
+ LOG(ERROR) << __func__ << "Failed to because we could not get a graphics buffer.";
+ status = ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
+ return false;
+ }
+ mStreamState = StreamState::RUNNING;
+ return true;
+}
+
+bool EvsCamera::postVideoStreamStart_locked(
+ const std::shared_ptr<evs::IEvsCameraStream>& /* receiver */,
+ ndk::ScopedAStatus& /* status */, std::unique_lock<std::mutex>& /* lck */) {
+ return true;
+}
+
+bool EvsCamera::preVideoStreamStop_locked(ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& /* lck */) {
+ if (mStreamState != StreamState::RUNNING) {
+ // Terminate the stop process because a stream is not running.
+ status = ndk::ScopedAStatus::ok();
+ return false;
+ }
+ mStreamState = StreamState::STOPPING;
+ return true;
+}
+
+bool EvsCamera::postVideoStreamStop_locked(ndk::ScopedAStatus& /* status */,
+ std::unique_lock<std::mutex>& /* lck */) {
+ mStreamState = StreamState::STOPPED;
+ return true;
+}
+
+ndk::ScopedAStatus EvsCamera::startVideoStream(
+ const std::shared_ptr<evs::IEvsCameraStream>& receiver) {
+ bool needShutdown = false;
+ auto status = ndk::ScopedAStatus::ok();
+ {
+ std::unique_lock lck(mMutex);
+ if (!preVideoStreamStart_locked(receiver, status, lck)) {
+ return status;
+ }
+
+ if ((!startVideoStreamImpl_locked(receiver, status, lck) ||
+ !postVideoStreamStart_locked(receiver, status, lck)) &&
+ !status.isOk()) {
+ needShutdown = true;
+ }
+ }
+ if (needShutdown) {
+ shutdown();
+ }
+ return status;
+}
+
+ndk::ScopedAStatus EvsCamera::stopVideoStream() {
+ bool needShutdown = false;
+ auto status = ndk::ScopedAStatus::ok();
+ {
+ std::unique_lock lck(mMutex);
+ if ((!preVideoStreamStop_locked(status, lck) || !stopVideoStreamImpl_locked(status, lck) ||
+ !postVideoStreamStop_locked(status, lck)) &&
+ !status.isOk()) {
+ needShutdown = true;
+ }
+ }
+ if (needShutdown) {
+ shutdown();
+ }
+ return status;
+}
+
+ndk::ScopedAStatus EvsCamera::pauseVideoStream() {
+ return ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::NOT_SUPPORTED));
+}
+
+ndk::ScopedAStatus EvsCamera::resumeVideoStream() {
+ return ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::NOT_SUPPORTED));
+}
+
+bool EvsCamera::setAvailableFrames_unsafe(const std::size_t bufferCount) {
+ if (bufferCount < 1) {
+ LOG(ERROR) << "Ignoring request to set buffer count to zero.";
+ return false;
+ }
+ if (bufferCount > kMaxBuffersInFlight) {
+ LOG(ERROR) << "Rejecting buffer request in excess of internal limit";
+ return false;
+ }
+
+ if (bufferCount > mAvailableFrames) {
+ bool success = true;
+ const std::size_t numBufferBeforeAlloc = mAvailableFrames;
+ for (int numBufferToAllocate = bufferCount - mAvailableFrames;
+ success && numBufferToAllocate > 0; --numBufferToAllocate) {
+ buffer_handle_t handle = nullptr;
+ const auto result = allocateOneFrame(&handle);
+ if (result != ::android::NO_ERROR || !handle) {
+ LOG(ERROR) << __func__ << ": Failed to allocate a graphics buffer. Error " << result
+ << ", handle: " << handle;
+ success = false;
+ break;
+ }
+ success &= increaseAvailableFrames_unsafe(handle);
+ }
+ if (!success) {
+ // Rollback when failure.
+ for (int numBufferToRelease = mAvailableFrames - numBufferBeforeAlloc;
+ numBufferToRelease > 0; --numBufferToRelease) {
+ decreaseAvailableFrames_unsafe();
+ }
+ return false;
+ }
+ } else {
+ for (int numBufferToRelease = mAvailableFrames - std::max(bufferCount, mFramesInUse);
+ numBufferToRelease > 0; --numBufferToRelease) {
+ decreaseAvailableFrames_unsafe();
+ }
+ if (mAvailableFrames > bufferCount) {
+ // This shouldn't happen with a properly behaving client because the client
+ // should only make this call after returning sufficient outstanding buffers
+ // to allow a clean resize.
+ LOG(ERROR) << "Buffer queue shrink failed, asked: " << bufferCount
+ << ", actual: " << mAvailableFrames
+ << " -- too many buffers currently in use?";
+ }
+ }
+ return true;
+}
+
+void EvsCamera::shutdown() {
+ stopVideoStream();
+ std::lock_guard lck(mMutex);
+ closeAllBuffers_unsafe();
+ mStreamState = StreamState::DEAD;
+}
+
+void EvsCamera::closeAllBuffers_unsafe() {
+ if (mFramesInUse > 0) {
+ LOG(WARNING) << __func__ << ": Closing while " << mFramesInUse
+ << " frame(s) are still in use.";
+ }
+ for (auto& buffer : mBuffers) {
+ freeOneFrame(buffer.handle);
+ buffer.handle = nullptr;
+ }
+ mBuffers.clear();
+ mBufferPosToId.clear();
+ mBufferIdToPos.clear();
+}
+
+std::pair<std::size_t, buffer_handle_t> EvsCamera::useBuffer_unsafe() {
+ if (mFramesInUse >= mAvailableFrames) {
+ DCHECK_EQ(mFramesInUse, mAvailableFrames);
+ return {kInvalidBufferID, nullptr};
+ }
+ const std::size_t pos = mFramesInUse++;
+ auto& buffer = mBuffers[pos];
+ DCHECK(!buffer.inUse);
+ DCHECK(buffer.handle);
+ buffer.inUse = true;
+ return {mBufferPosToId[pos], buffer.handle};
+}
+
+void EvsCamera::returnBuffer_unsafe(const std::size_t id) {
+ if (id >= mBuffers.size()) {
+ LOG(ERROR) << __func__ << ": ID out-of-bound. id: " << id
+ << " max: " << mBuffers.size() - 1;
+ return;
+ }
+ const std::size_t pos = mBufferIdToPos[id];
+
+ if (!mBuffers[pos].inUse) {
+ LOG(ERROR) << __func__ << ": Ignoring returning frame " << id << " which is already free.";
+ return;
+ }
+ DCHECK_LT(pos, mFramesInUse);
+ const std::size_t last_in_use_pos = --mFramesInUse;
+ swapBufferFrames_unsafe(pos, last_in_use_pos);
+ mBuffers[last_in_use_pos].inUse = false;
+}
+
+bool EvsCamera::increaseAvailableFrames_unsafe(const buffer_handle_t handle) {
+ if (mAvailableFrames >= kMaxBuffersInFlight) {
+ LOG(WARNING) << __func__ << ": The number of buffers has hit the upper limit ("
+ << kMaxBuffersInFlight << "). Stop increasing.";
+ return false;
+ }
+ const std::size_t pos = mAvailableFrames++;
+ if (mAvailableFrames > mBuffers.size()) {
+ const std::size_t oldBufferSize = mBuffers.size();
+ mBuffers.resize(mAvailableFrames);
+ mBufferPosToId.resize(mAvailableFrames);
+ mBufferIdToPos.resize(mAvailableFrames);
+ // Build position/ID mapping.
+ for (std::size_t idx = oldBufferSize; idx < mBuffers.size(); ++idx) {
+ mBufferPosToId[idx] = idx;
+ mBufferIdToPos[idx] = idx;
+ }
+ }
+ auto& buffer = mBuffers[pos];
+ DCHECK(!buffer.inUse);
+ DCHECK(!buffer.handle);
+ buffer.handle = handle;
+ return true;
+}
+
+bool EvsCamera::decreaseAvailableFrames_unsafe() {
+ if (mFramesInUse >= mAvailableFrames) {
+ DCHECK_EQ(mFramesInUse, mAvailableFrames);
+ return false;
+ }
+ const std::size_t pos = --mAvailableFrames;
+ auto& buffer = mBuffers[pos];
+ DCHECK(!buffer.inUse);
+ DCHECK(buffer.handle);
+ freeOneFrame(buffer.handle);
+ buffer.handle = nullptr;
+ return true;
+}
+
+void EvsCamera::swapBufferFrames_unsafe(const std::size_t pos1, const std::size_t pos2) {
+ if (pos1 == pos2) {
+ return;
+ }
+ if (pos1 >= mBuffers.size() || pos2 >= mBuffers.size()) {
+ LOG(ERROR) << __func__ << ": Index out-of-bound. pos1: " << pos1 << ", pos2: " << pos2
+ << ", buffer size: " << mBuffers.size();
+ return;
+ }
+ const std::size_t id1 = mBufferPosToId[pos1];
+ const std::size_t id2 = mBufferPosToId[pos2];
+ std::swap(mBufferPosToId[pos1], mBufferPosToId[pos2]);
+ std::swap(mBufferIdToPos[id1], mBufferIdToPos[id2]);
+ std::swap(mBuffers[pos1], mBuffers[pos2]);
+}
+
+} // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/src/EvsEnumerator.cpp b/automotive/evs/aidl/impl/default/src/EvsEnumerator.cpp
index 5178958..80e72a7 100644
--- a/automotive/evs/aidl/impl/default/src/EvsEnumerator.cpp
+++ b/automotive/evs/aidl/impl/default/src/EvsEnumerator.cpp
@@ -17,8 +17,9 @@
#include "EvsEnumerator.h"
#include "ConfigManager.h"
+#include "EvsAllCameras.h"
+#include "EvsCameraBase.h"
#include "EvsGlDisplay.h"
-#include "EvsMockCamera.h"
#include <aidl/android/hardware/automotive/evs/EvsResult.h>
#include <aidl/android/hardware/graphics/common/BufferUsage.h>
@@ -243,7 +244,7 @@
}
// Has this camera already been instantiated by another caller?
- std::shared_ptr<EvsMockCamera> pActiveCamera = pRecord->activeInstance.lock();
+ std::shared_ptr<EvsCameraBase> pActiveCamera = pRecord->activeInstance.lock();
if (pActiveCamera) {
LOG(WARNING) << "Killing previous camera because of new caller";
closeCamera(pActiveCamera);
@@ -253,12 +254,31 @@
if (!sConfigManager) {
pActiveCamera = EvsMockCamera::Create(id.data());
} else {
- pActiveCamera = EvsMockCamera::Create(id.data(), sConfigManager->getCameraInfo(id), &cfg);
+ auto& cameraInfo = sConfigManager->getCameraInfo(id);
+ switch (cameraInfo->deviceType) {
+ using DeviceType = ConfigManager::CameraInfo::DeviceType;
+
+ // Default to MOCK for backward compatibility.
+ case DeviceType::NONE:
+ case DeviceType::MOCK:
+ pActiveCamera = EvsMockCamera::Create(id.data(), cameraInfo, &cfg);
+ break;
+
+ case DeviceType::VIDEO:
+ pActiveCamera = EvsVideoEmulatedCamera::Create(id.data(), cameraInfo, &cfg);
+ break;
+
+ default:
+ LOG(ERROR) << __func__ << ": camera device type "
+ << static_cast<std::int32_t>(cameraInfo->deviceType)
+ << " is not supported.";
+ break;
+ }
}
pRecord->activeInstance = pActiveCamera;
if (!pActiveCamera) {
- LOG(ERROR) << "Failed to create new EvsMockCamera object for " << id;
+ LOG(ERROR) << "Failed to create new EVS camera object for " << id;
return ScopedAStatus::fromServiceSpecificError(
static_cast<int>(EvsResult::UNDERLYING_SERVICE_ERROR));
}
@@ -445,7 +465,7 @@
if (!pRecord) {
LOG(ERROR) << "Asked to close a camera whose name isn't recognized";
} else {
- std::shared_ptr<EvsMockCamera> pActiveCamera = pRecord->activeInstance.lock();
+ std::shared_ptr<EvsCameraBase> pActiveCamera = pRecord->activeInstance.lock();
if (!pActiveCamera) {
LOG(WARNING) << "Somehow a camera is being destroyed "
<< "when the enumerator didn't know one existed";
diff --git a/automotive/evs/aidl/impl/default/src/EvsMockCamera.cpp b/automotive/evs/aidl/impl/default/src/EvsMockCamera.cpp
index 797b221..ef43925 100644
--- a/automotive/evs/aidl/impl/default/src/EvsMockCamera.cpp
+++ b/automotive/evs/aidl/impl/default/src/EvsMockCamera.cpp
@@ -15,28 +15,25 @@
*/
#include "EvsMockCamera.h"
-#include "ConfigManager.h"
-#include "EvsEnumerator.h"
+
+#include <aidl/android/hardware/automotive/evs/EvsResult.h>
#include <aidlcommonsupport/NativeHandle.h>
+#include <android-base/logging.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
#include <utils/SystemClock.h>
+#include <cstddef>
+#include <cstdint>
#include <memory>
+#include <tuple>
namespace {
using ::aidl::android::hardware::graphics::common::BufferUsage;
using ::ndk::ScopedAStatus;
-// Arbitrary limit on number of graphics buffers allowed to be allocated
-// Safeguards against unreasonable resource consumption and provides a testable limit
-constexpr unsigned kMaxBuffersInFlight = 100;
-
-// Minimum number of buffers to run a video stream
-constexpr int kMinimumBuffersInFlight = 1;
-
// Colors for the colorbar test pattern in ABGR format
constexpr uint32_t kColors[] = {
0xFFFFFFFF, // white
@@ -56,7 +53,7 @@
EvsMockCamera::EvsMockCamera([[maybe_unused]] Sigil sigil, const char* id,
std::unique_ptr<ConfigManager::CameraInfo>& camInfo)
- : mFramesAllowed(0), mFramesInUse(0), mStreamState(STOPPED), mCameraInfo(camInfo) {
+ : mCameraInfo(camInfo) {
LOG(DEBUG) << __FUNCTION__;
/* set a camera id */
@@ -73,11 +70,6 @@
initializeParameters();
}
-EvsMockCamera::~EvsMockCamera() {
- LOG(DEBUG) << __FUNCTION__;
- shutdown();
-}
-
void EvsMockCamera::initializeParameters() {
mParams.emplace(
CameraParam::BRIGHTNESS,
@@ -90,35 +82,6 @@
new CameraParameterDesc(/* min= */ 0, /* max= */ 255, /* step= */ 1, /* value= */ 255));
}
-// This gets called if another caller "steals" ownership of the camera
-void EvsMockCamera::shutdown() {
- LOG(DEBUG) << __FUNCTION__;
-
- // Make sure our output stream is cleaned up
- // (It really should be already)
- stopVideoStream_impl();
-
- // Claim the lock while we work on internal state
- std::lock_guard lock(mAccessLock);
-
- // Drop all the graphics buffers we've been using
- if (mBuffers.size() > 0) {
- ::android::GraphicBufferAllocator& alloc(::android::GraphicBufferAllocator::get());
- for (auto&& rec : mBuffers) {
- if (rec.inUse) {
- LOG(WARNING) << "WARNING: releasing a buffer remotely owned.";
- }
- alloc.free(rec.handle);
- rec.handle = nullptr;
- }
- mBuffers.clear();
- }
-
- // Put this object into an unrecoverable error state since somebody else
- // is going to own the underlying camera now
- mStreamState = DEAD;
-}
-
// Methods from ::aidl::android::hardware::automotive::evs::IEvsCamera follow.
ScopedAStatus EvsMockCamera::getCameraInfo(CameraDesc* _aidl_return) {
LOG(DEBUG) << __FUNCTION__;
@@ -128,115 +91,6 @@
return ScopedAStatus::ok();
}
-ScopedAStatus EvsMockCamera::setMaxFramesInFlight(int32_t bufferCount) {
- LOG(DEBUG) << __FUNCTION__ << ", bufferCount = " << bufferCount;
- ;
-
- std::lock_guard lock(mAccessLock);
-
- // If we've been displaced by another owner of the camera, then we can't do anything else
- if (mStreamState == DEAD) {
- LOG(ERROR) << "Ignoring setMaxFramesInFlight call when camera has been lost.";
- return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST));
- }
-
- // We cannot function without at least one video buffer to send data
- if (bufferCount < 1) {
- LOG(ERROR) << "Ignoring setMaxFramesInFlight with less than one buffer requested.";
- return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
- }
-
- // Update our internal state
- if (!setAvailableFrames_Locked(bufferCount)) {
- LOG(ERROR) << "Failed to adjust the maximum number of frames in flight.";
- return ScopedAStatus::fromServiceSpecificError(
- static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
- }
-
- return ScopedAStatus::ok();
-}
-
-ScopedAStatus EvsMockCamera::startVideoStream(const std::shared_ptr<IEvsCameraStream>& cb) {
- LOG(DEBUG) << __FUNCTION__;
-
- if (!cb) {
- LOG(ERROR) << "A given stream callback is invalid.";
- return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::INVALID_ARG));
- }
-
- std::lock_guard lock(mAccessLock);
-
- // If we've been displaced by another owner of the camera, then we can't do anything else
- if (mStreamState == DEAD) {
- LOG(ERROR) << "Ignoring startVideoStream call when camera has been lost.";
- return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::OWNERSHIP_LOST));
- }
-
- if (mStreamState != STOPPED) {
- LOG(ERROR) << "Ignoring startVideoStream call when a stream is already running.";
- return ScopedAStatus::fromServiceSpecificError(
- static_cast<int>(EvsResult::STREAM_ALREADY_RUNNING));
- }
-
- // If the client never indicated otherwise, configure ourselves for a single streaming buffer
- if (mFramesAllowed < kMinimumBuffersInFlight &&
- !setAvailableFrames_Locked(kMinimumBuffersInFlight)) {
- LOG(ERROR) << "Failed to start stream because we couldn't get a graphics buffer";
- return ScopedAStatus::fromServiceSpecificError(
- static_cast<int>(EvsResult::BUFFER_NOT_AVAILABLE));
- }
-
- // Record the user's callback for use when we have a frame ready
- mStream = cb;
-
- // Start the frame generation thread
- mStreamState = RUNNING;
- mCaptureThread = std::thread([this]() { generateFrames(); });
-
- return ScopedAStatus::ok();
-}
-
-ScopedAStatus EvsMockCamera::doneWithFrame(const std::vector<BufferDesc>& list) {
- std::lock_guard lock(mAccessLock);
- for (const auto& desc : list) {
- returnBufferLocked(desc.bufferId);
- }
-
- return ScopedAStatus::ok();
-}
-
-ScopedAStatus EvsMockCamera::stopVideoStream() {
- LOG(DEBUG) << __FUNCTION__;
- return stopVideoStream_impl();
-}
-
-ScopedAStatus EvsMockCamera::stopVideoStream_impl() {
- std::unique_lock lock(mAccessLock);
-
- if (mStreamState != RUNNING) {
- // Safely return here because a stream is not running.
- return ScopedAStatus::ok();
- }
-
- // Tell the GenerateFrames loop we want it to stop
- mStreamState = STOPPING;
-
- // Block outside the mutex until the "stop" flag has been acknowledged
- // We won't send any more frames, but the client might still get some already in flight
- LOG(DEBUG) << "Waiting for stream thread to end...";
- lock.unlock();
- if (mCaptureThread.joinable()) {
- mCaptureThread.join();
- }
- lock.lock();
-
- mStreamState = STOPPED;
- mStream = nullptr;
- LOG(DEBUG) << "Stream marked STOPPED.";
-
- return ScopedAStatus::ok();
-}
-
ScopedAStatus EvsMockCamera::getExtendedInfo(int32_t opaqueIdentifier,
std::vector<uint8_t>* opaqueValue) {
const auto it = mExtInfo.find(opaqueIdentifier);
@@ -264,14 +118,6 @@
return ScopedAStatus::ok();
}
-ScopedAStatus EvsMockCamera::pauseVideoStream() {
- return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::NOT_SUPPORTED));
-}
-
-ScopedAStatus EvsMockCamera::resumeVideoStream() {
- return ScopedAStatus::fromServiceSpecificError(static_cast<int>(EvsResult::NOT_SUPPORTED));
-}
-
ScopedAStatus EvsMockCamera::setPrimaryClient() {
/* Because EVS HW module reference implementation expects a single client at
* a time, this returns a success code always.
@@ -346,232 +192,27 @@
return ScopedAStatus::ok();
}
-ScopedAStatus EvsMockCamera::importExternalBuffers(const std::vector<BufferDesc>& buffers,
- int32_t* _aidl_return) {
- size_t numBuffersToAdd = buffers.size();
- if (numBuffersToAdd < 1) {
- LOG(DEBUG) << "Ignoring a request to import external buffers with an empty list.";
- return ScopedAStatus::ok();
- }
-
- std::lock_guard lock(mAccessLock);
- if (numBuffersToAdd > (kMaxBuffersInFlight - mFramesAllowed)) {
- numBuffersToAdd -= (kMaxBuffersInFlight - mFramesAllowed);
- LOG(WARNING) << "Exceed the limit on the number of buffers. " << numBuffersToAdd
- << " buffers will be imported only.";
- }
-
- ::android::GraphicBufferMapper& mapper = ::android::GraphicBufferMapper::get();
- const size_t before = mFramesAllowed;
- for (size_t i = 0; i < numBuffersToAdd; ++i) {
- auto& b = buffers[i];
- const AHardwareBuffer_Desc* pDesc =
- reinterpret_cast<const AHardwareBuffer_Desc*>(&b.buffer.description);
-
- buffer_handle_t handleToImport = ::android::dupFromAidl(b.buffer.handle);
- buffer_handle_t handleToStore = nullptr;
- if (handleToImport == nullptr) {
- LOG(WARNING) << "Failed to duplicate a memory handle. Ignoring a buffer " << b.bufferId;
- continue;
- }
-
- ::android::status_t result =
- mapper.importBuffer(handleToImport, pDesc->width, pDesc->height, pDesc->layers,
- pDesc->format, pDesc->usage, pDesc->stride, &handleToStore);
- if (result != ::android::NO_ERROR || handleToStore == nullptr) {
- LOG(WARNING) << "Failed to import a buffer " << b.bufferId;
- continue;
- }
-
- bool stored = false;
- for (auto&& rec : mBuffers) {
- if (rec.handle != nullptr) {
- continue;
- }
-
- // Use this existing entry.
- rec.handle = handleToStore;
- rec.inUse = false;
- stored = true;
- break;
- }
-
- if (!stored) {
- // Add a BufferRecord wrapping this handle to our set of available buffers.
- mBuffers.push_back(BufferRecord(handleToStore));
- }
- ++mFramesAllowed;
- }
-
- *_aidl_return = mFramesAllowed - before;
- return ScopedAStatus::ok();
-}
-
-bool EvsMockCamera::setAvailableFrames_Locked(unsigned bufferCount) {
- if (bufferCount < 1) {
- LOG(ERROR) << "Ignoring request to set buffer count to zero";
- return false;
- }
- if (bufferCount > kMaxBuffersInFlight) {
- LOG(ERROR) << "Rejecting buffer request in excess of internal limit";
- return false;
- }
-
- // Is an increase required?
- if (mFramesAllowed < bufferCount) {
- // An increase is required
- auto needed = bufferCount - mFramesAllowed;
- LOG(INFO) << "Allocating " << needed << " buffers for camera frames";
-
- auto added = increaseAvailableFrames_Locked(needed);
- if (added != needed) {
- // If we didn't add all the frames we needed, then roll back to the previous state
- LOG(ERROR) << "Rolling back to previous frame queue size";
- decreaseAvailableFrames_Locked(added);
- return false;
- }
- } else if (mFramesAllowed > bufferCount) {
- // A decrease is required
- auto framesToRelease = mFramesAllowed - bufferCount;
- LOG(INFO) << "Returning " << framesToRelease << " camera frame buffers";
-
- auto released = decreaseAvailableFrames_Locked(framesToRelease);
- if (released != framesToRelease) {
- // This shouldn't happen with a properly behaving client because the client
- // should only make this call after returning sufficient outstanding buffers
- // to allow a clean resize.
- LOG(ERROR) << "Buffer queue shrink failed -- too many buffers currently in use?";
- }
- }
-
- return true;
-}
-
-unsigned EvsMockCamera::increaseAvailableFrames_Locked(unsigned numToAdd) {
- // Acquire the graphics buffer allocator
- ::android::GraphicBufferAllocator& alloc(::android::GraphicBufferAllocator::get());
-
- unsigned added = 0;
- while (added < numToAdd) {
- unsigned pixelsPerLine = 0;
- buffer_handle_t memHandle = nullptr;
- auto result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage, &memHandle,
- &pixelsPerLine, 0, "EvsMockCamera");
- if (result != ::android::NO_ERROR) {
- LOG(ERROR) << "Error " << result << " allocating " << mWidth << " x " << mHeight
- << " graphics buffer";
- break;
- }
- if (memHandle == nullptr) {
- LOG(ERROR) << "We didn't get a buffer handle back from the allocator";
- break;
- }
- if (mStride > 0) {
- if (mStride != pixelsPerLine) {
- LOG(ERROR) << "We did not expect to get buffers with different strides!";
- }
- } else {
- // Gralloc defines stride in terms of pixels per line
- mStride = pixelsPerLine;
- }
-
- // Find a place to store the new buffer
- auto stored = false;
- for (auto&& rec : mBuffers) {
- if (rec.handle == nullptr) {
- // Use this existing entry
- rec.handle = memHandle;
- rec.inUse = false;
- stored = true;
- break;
- }
- }
- if (!stored) {
- // Add a BufferRecord wrapping this handle to our set of available buffers
- mBuffers.push_back(BufferRecord(memHandle));
- }
-
- ++mFramesAllowed;
- ++added;
- }
-
- return added;
-}
-
-unsigned EvsMockCamera::decreaseAvailableFrames_Locked(unsigned numToRemove) {
- // Acquire the graphics buffer allocator
- ::android::GraphicBufferAllocator& alloc(::android::GraphicBufferAllocator::get());
-
- unsigned removed = 0;
- for (auto&& rec : mBuffers) {
- // Is this record not in use, but holding a buffer that we can free?
- if ((rec.inUse == false) && (rec.handle != nullptr)) {
- // Release buffer and update the record so we can recognize it as "empty"
- alloc.free(rec.handle);
- rec.handle = nullptr;
-
- --mFramesAllowed;
- ++removed;
-
- if (removed == numToRemove) {
- break;
- }
- }
- }
-
- return removed;
-}
-
// This is the asynchronous frame generation thread that runs in parallel with the
// main serving thread. There is one for each active camera instance.
void EvsMockCamera::generateFrames() {
LOG(DEBUG) << "Frame generation loop started.";
- unsigned idx = 0;
while (true) {
- bool timeForFrame = false;
const nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-
- // Lock scope for updating shared state
+ std::size_t bufferId = kInvalidBufferID;
+ buffer_handle_t bufferHandle = nullptr;
{
- std::lock_guard lock(mAccessLock);
-
- if (mStreamState != RUNNING) {
- // Break out of our main thread loop
+ std::lock_guard lock(mMutex);
+ if (mStreamState != StreamState::RUNNING) {
break;
}
-
- // Are we allowed to issue another buffer?
- if (mFramesInUse >= mFramesAllowed) {
- // Can't do anything right now -- skip this frame
- LOG(WARNING) << "Skipped a frame because too many are in flight.";
- } else {
- // Identify an available buffer to fill
- for (idx = 0; idx < mBuffers.size(); idx++) {
- if (!mBuffers[idx].inUse) {
- if (mBuffers[idx].handle != nullptr) {
- // Found an available record, so stop looking
- break;
- }
- }
- }
- if (idx >= mBuffers.size()) {
- // This shouldn't happen since we already checked mFramesInUse vs mFramesAllowed
- ALOGE("Failed to find an available buffer slot\n");
- } else {
- // We're going to make the frame busy
- mBuffers[idx].inUse = true;
- mFramesInUse++;
- timeForFrame = true;
- }
- }
+ std::tie(bufferId, bufferHandle) = useBuffer_unsafe();
}
- if (timeForFrame) {
+ if (bufferHandle != nullptr) {
using AidlPixelFormat = ::aidl::android::hardware::graphics::common::PixelFormat;
// Assemble the buffer description we'll transmit below
- buffer_handle_t memHandle = mBuffers[idx].handle;
BufferDesc newBuffer = {
.buffer =
{
@@ -584,39 +225,31 @@
.usage = static_cast<BufferUsage>(mUsage),
.stride = static_cast<int32_t>(mStride),
},
- .handle = ::android::dupToAidl(memHandle),
+ .handle = ::android::dupToAidl(bufferHandle),
},
- .bufferId = static_cast<int32_t>(idx),
+ .bufferId = static_cast<int32_t>(bufferId),
.deviceId = mDescription.id,
.timestamp = static_cast<int64_t>(::android::elapsedRealtimeNano() *
1e+3), // timestamps is in microseconds
};
// Write test data into the image buffer
- fillMockFrame(memHandle, reinterpret_cast<const AHardwareBuffer_Desc*>(
- &newBuffer.buffer.description));
+ fillMockFrame(bufferHandle, reinterpret_cast<const AHardwareBuffer_Desc*>(
+ &newBuffer.buffer.description));
+
+ std::vector<BufferDesc> frames;
+ frames.push_back(std::move(newBuffer));
// Issue the (asynchronous) callback to the client -- can't be holding the lock
- auto flag = false;
- if (mStream) {
- std::vector<BufferDesc> frames;
- frames.push_back(std::move(newBuffer));
- flag = mStream->deliverFrame(frames).isOk();
- }
-
- if (flag) {
- LOG(DEBUG) << "Delivered " << memHandle << ", id = " << mBuffers[idx].handle;
+ if (mStream && mStream->deliverFrame(frames).isOk()) {
+ LOG(DEBUG) << "Delivered " << bufferHandle << ", id = " << bufferId;
} else {
// This can happen if the client dies and is likely unrecoverable.
// To avoid consuming resources generating failing calls, we stop sending
// frames. Note, however, that the stream remains in the "STREAMING" state
// until cleaned up on the main thread.
LOG(ERROR) << "Frame delivery call failed in the transport layer.";
-
- // Since we didn't actually deliver it, mark the frame as available
- std::lock_guard<std::mutex> lock(mAccessLock);
- mBuffers[idx].inUse = false;
- mFramesInUse--;
+ doneWithFrame(frames);
}
}
@@ -671,34 +304,45 @@
mapper.unlock(handle);
}
-void EvsMockCamera::returnBufferLocked(const uint32_t bufferId) {
- if (bufferId >= mBuffers.size()) {
- ALOGE("ignoring doneWithFrame called with invalid bufferId %d (max is %zu)", bufferId,
- mBuffers.size() - 1);
- return;
+::android::status_t EvsMockCamera::allocateOneFrame(buffer_handle_t* handle) {
+ static auto& alloc = ::android::GraphicBufferAllocator::get();
+ unsigned pixelsPerLine = 0;
+ const auto result = alloc.allocate(mWidth, mHeight, mFormat, 1, mUsage, handle, &pixelsPerLine,
+ 0, "EvsMockCamera");
+ if (mStride < mWidth) {
+ // Gralloc defines stride in terms of pixels per line
+ mStride = pixelsPerLine;
+ } else if (mStride != pixelsPerLine) {
+ LOG(ERROR) << "We did not expect to get buffers with different strides!";
}
+ return result;
+}
- if (!mBuffers[bufferId].inUse) {
- ALOGE("ignoring doneWithFrame called on frame %d which is already free", bufferId);
- return;
+bool EvsMockCamera::startVideoStreamImpl_locked(
+ const std::shared_ptr<evs::IEvsCameraStream>& receiver, ndk::ScopedAStatus& /* status */,
+ std::unique_lock<std::mutex>& /* lck */) {
+ mStream = receiver;
+ mCaptureThread = std::thread([this]() { generateFrames(); });
+ return true;
+}
+
+bool EvsMockCamera::stopVideoStreamImpl_locked(ndk::ScopedAStatus& /* status */,
+ std::unique_lock<std::mutex>& lck) {
+ lck.unlock();
+ if (mCaptureThread.joinable()) {
+ mCaptureThread.join();
}
+ lck.lock();
+ return true;
+}
- // Mark the frame as available
- mBuffers[bufferId].inUse = false;
- mFramesInUse--;
-
- // If this frame's index is high in the array, try to move it down
- // to improve locality after mFramesAllowed has been reduced.
- if (bufferId >= mFramesAllowed) {
- // Find an empty slot lower in the array (which should always exist in this case)
- for (auto&& rec : mBuffers) {
- if (rec.handle == nullptr) {
- rec.handle = mBuffers[bufferId].handle;
- mBuffers[bufferId].handle = nullptr;
- break;
- }
- }
+bool EvsMockCamera::postVideoStreamStop_locked(ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) {
+ if (!Base::postVideoStreamStop_locked(status, lck)) {
+ return false;
}
+ mStream = nullptr;
+ return true;
}
std::shared_ptr<EvsMockCamera> EvsMockCamera::Create(const char* deviceName) {
diff --git a/automotive/evs/aidl/impl/default/src/EvsVideoEmulatedCamera.cpp b/automotive/evs/aidl/impl/default/src/EvsVideoEmulatedCamera.cpp
new file mode 100644
index 0000000..f198a64
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/src/EvsVideoEmulatedCamera.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EvsVideoEmulatedCamera.h"
+
+#include <aidl/android/hardware/automotive/evs/EvsResult.h>
+
+#include <android-base/logging.h>
+
+#include <cstddef>
+#include <cstdint>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+EvsVideoEmulatedCamera::EvsVideoEmulatedCamera(Sigil, const char* deviceName,
+ std::unique_ptr<ConfigManager::CameraInfo>& camInfo)
+ : mCameraInfo(camInfo) {
+ mDescription.id = deviceName;
+
+ /* set camera metadata */
+ if (camInfo) {
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(camInfo->characteristics);
+ const size_t len = get_camera_metadata_size(camInfo->characteristics);
+ mDescription.metadata.insert(mDescription.metadata.end(), ptr, ptr + len);
+ }
+
+ initializeParameters();
+}
+
+void EvsVideoEmulatedCamera::initializeParameters() {
+ mParams.emplace(
+ CameraParam::BRIGHTNESS,
+ new CameraParameterDesc(/* min= */ 0, /* max= */ 255, /* step= */ 1, /* value= */ 255));
+ mParams.emplace(
+ CameraParam::CONTRAST,
+ new CameraParameterDesc(/* min= */ 0, /* max= */ 255, /* step= */ 1, /* value= */ 255));
+ mParams.emplace(
+ CameraParam::SHARPNESS,
+ new CameraParameterDesc(/* min= */ 0, /* max= */ 255, /* step= */ 1, /* value= */ 255));
+}
+
+::android::status_t EvsVideoEmulatedCamera::allocateOneFrame(buffer_handle_t* /* handle */) {
+ LOG(FATAL) << __func__ << ": Not implemented yet.";
+ return ::android::UNKNOWN_ERROR;
+}
+
+bool EvsVideoEmulatedCamera::startVideoStreamImpl_locked(
+ const std::shared_ptr<evs::IEvsCameraStream>& /* receiver */,
+ ndk::ScopedAStatus& /* status */, std::unique_lock<std::mutex>& /* lck */) {
+ LOG(FATAL) << __func__ << ": Not implemented yet.";
+ return false;
+}
+
+bool EvsVideoEmulatedCamera::stopVideoStreamImpl_locked(ndk::ScopedAStatus& /* status */,
+ std::unique_lock<std::mutex>& /* lck */) {
+ LOG(FATAL) << __func__ << ": Not implemented yet.";
+ return false;
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::forcePrimaryClient(
+ const std::shared_ptr<evs::IEvsDisplay>& /* display */) {
+ /* Because EVS HW module reference implementation expects a single client at
+ * a time, this returns a success code always.
+ */
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getCameraInfo(evs::CameraDesc* _aidl_return) {
+ *_aidl_return = mDescription;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getExtendedInfo(int32_t opaqueIdentifier,
+ std::vector<uint8_t>* value) {
+ const auto it = mExtInfo.find(opaqueIdentifier);
+ if (it == mExtInfo.end()) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::INVALID_ARG));
+ } else {
+ *value = mExtInfo[opaqueIdentifier];
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getIntParameter(evs::CameraParam id,
+ std::vector<int32_t>* value) {
+ const auto it = mParams.find(id);
+ if (it == mParams.end()) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::NOT_SUPPORTED));
+ }
+ value->push_back(it->second->value);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getIntParameterRange(evs::CameraParam id,
+ evs::ParameterRange* _aidl_return) {
+ const auto it = mParams.find(id);
+ if (it == mParams.end()) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::NOT_SUPPORTED));
+ }
+ _aidl_return->min = it->second->range.min;
+ _aidl_return->max = it->second->range.max;
+ _aidl_return->step = it->second->range.step;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getParameterList(
+ std::vector<evs::CameraParam>* _aidl_return) {
+ if (mCameraInfo) {
+ _aidl_return->resize(mCameraInfo->controls.size());
+ std::size_t idx = 0;
+ for (const auto& [name, range] : mCameraInfo->controls) {
+ (*_aidl_return)[idx++] = name;
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::getPhysicalCameraInfo(const std::string& /* deviceId */,
+ evs::CameraDesc* _aidl_return) {
+ return getCameraInfo(_aidl_return);
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::setExtendedInfo(
+ int32_t opaqueIdentifier, const std::vector<uint8_t>& opaqueValue) {
+ mExtInfo.insert_or_assign(opaqueIdentifier, opaqueValue);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::setIntParameter(evs::CameraParam id, int32_t value,
+ std::vector<int32_t>* effectiveValue) {
+ const auto it = mParams.find(id);
+ if (it == mParams.end()) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::NOT_SUPPORTED));
+ }
+ // Rounding down to the closest value.
+ int32_t candidate = value / it->second->range.step * it->second->range.step;
+ if (candidate < it->second->range.min || candidate > it->second->range.max) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int>(EvsResult::INVALID_ARG));
+ }
+ it->second->value = candidate;
+ effectiveValue->push_back(candidate);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::setPrimaryClient() {
+ /* Because EVS HW module reference implementation expects a single client at
+ * a time, this returns a success code always.
+ */
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EvsVideoEmulatedCamera::unsetPrimaryClient() {
+ /* Because EVS HW module reference implementation expects a single client at
+ * a time, there is no chance that this is called by the secondary client and
+ * therefore returns a success code always.
+ */
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EvsVideoEmulatedCamera> EvsVideoEmulatedCamera::Create(const char* deviceName) {
+ std::unique_ptr<ConfigManager::CameraInfo> nullCamInfo = nullptr;
+ return Create(deviceName, nullCamInfo);
+}
+
+std::shared_ptr<EvsVideoEmulatedCamera> EvsVideoEmulatedCamera::Create(
+ const char* deviceName, std::unique_ptr<ConfigManager::CameraInfo>& camInfo,
+ const evs::Stream* /* streamCfg */) {
+ std::shared_ptr<EvsVideoEmulatedCamera> c =
+ ndk::SharedRefBase::make<EvsVideoEmulatedCamera>(Sigil{}, deviceName, camInfo);
+ if (!c) {
+ LOG(ERROR) << "Failed to instantiate EvsVideoEmulatedCamera.";
+ return nullptr;
+ }
+ c->mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary test value
+ return c;
+}
+
+EvsVideoEmulatedCamera::~EvsVideoEmulatedCamera() {}
+
+} // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/tests/EvsCameraBufferTest.cpp b/automotive/evs/aidl/impl/default/tests/EvsCameraBufferTest.cpp
new file mode 100644
index 0000000..8b4676e
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/tests/EvsCameraBufferTest.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EvsCamera.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <cstdint>
+#include <unordered_set>
+#include <vector>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class EvsCameraForTest : public EvsCamera {
+ public:
+ using EvsCamera::increaseAvailableFrames_unsafe;
+ using EvsCamera::returnBuffer_unsafe;
+ using EvsCamera::useBuffer_unsafe;
+
+ ~EvsCameraForTest() override { shutdown(); }
+
+ ::android::status_t allocateOneFrame(buffer_handle_t* handle) override {
+ static std::intptr_t handle_cnt = 0;
+ *handle = reinterpret_cast<buffer_handle_t>(++handle_cnt);
+ return ::android::OK;
+ }
+
+ void freeOneFrame(const buffer_handle_t /* handle */) override {
+ // Nothing to free because the handles are fake.
+ }
+
+ void checkBufferOrder() {
+ for (std::size_t idx = 0; idx < mBuffers.size(); ++idx) {
+ const auto& buffer = mBuffers[idx];
+ EXPECT_EQ(idx < mFramesInUse, buffer.inUse);
+ EXPECT_EQ(idx < mAvailableFrames, buffer.handle != nullptr);
+ EXPECT_LE(mFramesInUse, mAvailableFrames);
+ }
+ }
+
+ MOCK_METHOD(::ndk::ScopedAStatus, forcePrimaryClient,
+ (const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>&
+ in_display),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getCameraInfo,
+ (::aidl::android::hardware::automotive::evs::CameraDesc * _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getExtendedInfo,
+ (int32_t in_opaqueIdentifier, std::vector<uint8_t>* _aidl_return), (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getIntParameter,
+ (::aidl::android::hardware::automotive::evs::CameraParam in_id,
+ std::vector<int32_t>* _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getIntParameterRange,
+ (::aidl::android::hardware::automotive::evs::CameraParam in_id,
+ ::aidl::android::hardware::automotive::evs::ParameterRange* _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getParameterList,
+ (std::vector<::aidl::android::hardware::automotive::evs::CameraParam> *
+ _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getPhysicalCameraInfo,
+ (const std::string& in_deviceId,
+ ::aidl::android::hardware::automotive::evs::CameraDesc* _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, setExtendedInfo,
+ (int32_t in_opaqueIdentifier, const std::vector<uint8_t>& in_opaqueValue),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, setIntParameter,
+ (::aidl::android::hardware::automotive::evs::CameraParam in_id, int32_t in_value,
+ std::vector<int32_t>* _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, setPrimaryClient, (), (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, unsetPrimaryClient, (), (override));
+ MOCK_METHOD(bool, startVideoStreamImpl_locked,
+ (const std::shared_ptr<evs::IEvsCameraStream>& receiver, ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck),
+ (override));
+ MOCK_METHOD(bool, stopVideoStreamImpl_locked,
+ (ndk::ScopedAStatus & status, std::unique_lock<std::mutex>& lck), (override));
+};
+
+TEST(EvsCameraBufferTest, ChangeBufferPoolSize) {
+ auto evsCam = ndk::SharedRefBase::make<EvsCameraForTest>();
+ EXPECT_TRUE(evsCam->setMaxFramesInFlight(100).isOk());
+ evsCam->checkBufferOrder();
+ EXPECT_TRUE(evsCam->setMaxFramesInFlight(50).isOk());
+ evsCam->checkBufferOrder();
+
+ // 2 buffers in use.
+ const auto [id1, handle1] = evsCam->useBuffer_unsafe();
+ const auto [id2, handle2] = evsCam->useBuffer_unsafe();
+ std::ignore = evsCam->useBuffer_unsafe();
+
+ // It allows you to set the buffer pool size to 1, but it will keep the space for the in use
+ // buffers.
+ EXPECT_TRUE(evsCam->setMaxFramesInFlight(1).isOk());
+ evsCam->checkBufferOrder();
+
+ evsCam->returnBuffer_unsafe(id1);
+ evsCam->checkBufferOrder();
+ evsCam->returnBuffer_unsafe(id2);
+ evsCam->checkBufferOrder();
+}
+
+TEST(EvsCameraBufferTest, UseAndReturn) {
+ constexpr std::size_t kNumOfHandles = 20;
+ auto evsCam = ndk::SharedRefBase::make<EvsCameraForTest>();
+
+ // Our "fake handles" of this test case is 1 to kNumOfHandles.
+ for (std::size_t i = 1; i <= kNumOfHandles; ++i) {
+ evsCam->increaseAvailableFrames_unsafe(reinterpret_cast<buffer_handle_t>(i));
+ }
+ evsCam->checkBufferOrder();
+
+ {
+ std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
+ std::unordered_set<std::size_t> inUseIDs;
+ std::unordered_set<std::intptr_t> inUseHandles;
+ for (std::size_t i = 0; i < kNumOfHandles; ++i) {
+ const auto [id, handle] = evsCam->useBuffer_unsafe();
+ const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
+ EXPECT_TRUE(EvsCamera::IsBufferIDValid(id));
+ EXPECT_NE(handle, nullptr);
+ EXPECT_LT(id, kNumOfHandles);
+
+ // handleInt must be between [1, kNumOfHandles] as we "allocated" above.
+ EXPECT_LT(0u, handleInt);
+ EXPECT_LE(handleInt, kNumOfHandles);
+
+ inUseIDHandlePairs.push_back({id, handleInt});
+ EXPECT_TRUE(inUseIDs.insert(id).second);
+ EXPECT_TRUE(inUseHandles.insert(handleInt).second);
+ evsCam->checkBufferOrder();
+ }
+ // Return buffers in the order of acquiring.
+ for (const auto [id, handleInt] : inUseIDHandlePairs) {
+ evsCam->returnBuffer_unsafe(id);
+ evsCam->checkBufferOrder();
+ }
+ }
+
+ {
+ std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
+ std::unordered_set<std::size_t> inUseIDs;
+ std::unordered_set<std::intptr_t> inUseHandles;
+ for (std::size_t i = 0; i < kNumOfHandles; ++i) {
+ const auto [id, handle] = evsCam->useBuffer_unsafe();
+ const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
+ EXPECT_TRUE(EvsCamera::IsBufferIDValid(id));
+ EXPECT_NE(handle, nullptr);
+ EXPECT_LT(id, kNumOfHandles);
+
+ // handleInt must be between [1, kNumOfHandles] as we "allocated" above.
+ EXPECT_LT(0u, handleInt);
+ EXPECT_LE(handleInt, kNumOfHandles);
+
+ inUseIDHandlePairs.push_back({id, handleInt});
+ EXPECT_TRUE(inUseIDs.insert(id).second);
+ EXPECT_TRUE(inUseHandles.insert(handleInt).second);
+ evsCam->checkBufferOrder();
+ }
+ // Return buffers in the reverse order of acquiring.
+ std::reverse(inUseIDHandlePairs.begin(), inUseIDHandlePairs.end());
+ for (const auto [id, handleInt] : inUseIDHandlePairs) {
+ evsCam->returnBuffer_unsafe(id);
+ evsCam->checkBufferOrder();
+ }
+ }
+
+ {
+ // Making sure the handles are still in [1, kNumOfHandles] and IDs are still [0,
+ // kNumOfHandles). The mapping may be different, though.
+ std::vector<std::pair<std::size_t, std::intptr_t>> inUseIDHandlePairs;
+ std::unordered_set<std::size_t> inUseIDs;
+ std::unordered_set<std::intptr_t> inUseHandles;
+ for (std::size_t i = 0; i < kNumOfHandles; ++i) {
+ const auto [id, handle] = evsCam->useBuffer_unsafe();
+ const std::size_t handleInt = reinterpret_cast<std::size_t>(handle);
+ EXPECT_TRUE(EvsCamera::IsBufferIDValid(id));
+ EXPECT_NE(handle, nullptr);
+ EXPECT_LT(id, kNumOfHandles);
+
+ // handleInt must be between [1, kNumOfHandles] as we "allocated" above.
+ EXPECT_LT(0u, handleInt);
+ EXPECT_LE(handleInt, kNumOfHandles);
+
+ inUseIDHandlePairs.push_back({id, handleInt});
+ EXPECT_TRUE(inUseIDs.insert(id).second);
+ EXPECT_TRUE(inUseHandles.insert(handleInt).second);
+ evsCam->checkBufferOrder();
+ }
+ }
+}
+
+} // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/evs/aidl/impl/default/tests/EvsCameraStateTest.cpp b/automotive/evs/aidl/impl/default/tests/EvsCameraStateTest.cpp
new file mode 100644
index 0000000..1925c79
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/tests/EvsCameraStateTest.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "EvsCamera.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <cstdint>
+#include <unordered_set>
+#include <vector>
+
+namespace aidl::android::hardware::automotive::evs::implementation {
+
+class EvsCameraForTest : public EvsCamera {
+ private:
+ using Base = EvsCamera;
+
+ public:
+ using EvsCamera::mStreamState;
+ using EvsCamera::shutdown;
+ using EvsCamera::StreamState;
+
+ ~EvsCameraForTest() override { shutdown(); }
+
+ ::android::status_t allocateOneFrame(buffer_handle_t* handle) override {
+ static std::intptr_t handle_cnt = 0;
+ *handle = reinterpret_cast<buffer_handle_t>(++handle_cnt);
+ return ::android::OK;
+ }
+
+ void freeOneFrame(const buffer_handle_t /* handle */) override {
+ // Nothing to free because the handles are fake.
+ }
+
+ bool preVideoStreamStart_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+ ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) override {
+ mPreStartCalled = true;
+ EXPECT_EQ(mStreamState, StreamState::STOPPED);
+ EXPECT_FALSE(mStreamStarted);
+ EXPECT_FALSE(mStreamStopped);
+ return Base::preVideoStreamStart_locked(receiver, status, lck);
+ }
+
+ bool startVideoStreamImpl_locked(const std::shared_ptr<evs::IEvsCameraStream>& /* receiver */,
+ ndk::ScopedAStatus& /* status */,
+ std::unique_lock<std::mutex>& /* lck */) override {
+ EXPECT_EQ(mStreamState, StreamState::RUNNING);
+ EXPECT_FALSE(mStreamStarted);
+ EXPECT_FALSE(mStreamStopped);
+ mStreamStarted = true;
+ return true;
+ }
+
+ bool postVideoStreamStart_locked(const std::shared_ptr<evs::IEvsCameraStream>& receiver,
+ ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) override {
+ mPostStartCalled = true;
+ EXPECT_EQ(mStreamState, StreamState::RUNNING);
+ EXPECT_TRUE(mStreamStarted);
+ EXPECT_FALSE(mStreamStopped);
+ return Base::postVideoStreamStart_locked(receiver, status, lck);
+ }
+
+ bool preVideoStreamStop_locked(ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) override {
+ // Skip the check if stop was called before.
+ if (!mPreStopCalled) {
+ mPreStopCalled = true;
+ EXPECT_EQ(mStreamState, StreamState::RUNNING);
+ EXPECT_TRUE(mStreamStarted);
+ EXPECT_FALSE(mStreamStopped);
+ }
+ return Base::preVideoStreamStop_locked(status, lck);
+ }
+
+ bool stopVideoStreamImpl_locked(ndk::ScopedAStatus& /* status */,
+ std::unique_lock<std::mutex>& /* lck */) override {
+ EXPECT_EQ(mStreamState, StreamState::STOPPING);
+ EXPECT_TRUE(mStreamStarted);
+ EXPECT_FALSE(mStreamStopped);
+ mStreamStopped = true;
+ return true;
+ }
+
+ bool postVideoStreamStop_locked(ndk::ScopedAStatus& status,
+ std::unique_lock<std::mutex>& lck) override {
+ mPostStopCalled = true;
+ const auto ret = Base::postVideoStreamStop_locked(status, lck);
+ EXPECT_EQ(mStreamState, StreamState::STOPPED);
+ EXPECT_TRUE(mStreamStarted);
+ EXPECT_TRUE(mStreamStopped);
+ return ret;
+ }
+
+ MOCK_METHOD(::ndk::ScopedAStatus, forcePrimaryClient,
+ (const std::shared_ptr<::aidl::android::hardware::automotive::evs::IEvsDisplay>&
+ in_display),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getCameraInfo,
+ (::aidl::android::hardware::automotive::evs::CameraDesc * _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getExtendedInfo,
+ (int32_t in_opaqueIdentifier, std::vector<uint8_t>* _aidl_return), (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getIntParameter,
+ (::aidl::android::hardware::automotive::evs::CameraParam in_id,
+ std::vector<int32_t>* _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getIntParameterRange,
+ (::aidl::android::hardware::automotive::evs::CameraParam in_id,
+ ::aidl::android::hardware::automotive::evs::ParameterRange* _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getParameterList,
+ (std::vector<::aidl::android::hardware::automotive::evs::CameraParam> *
+ _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getPhysicalCameraInfo,
+ (const std::string& in_deviceId,
+ ::aidl::android::hardware::automotive::evs::CameraDesc* _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, setExtendedInfo,
+ (int32_t in_opaqueIdentifier, const std::vector<uint8_t>& in_opaqueValue),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, setIntParameter,
+ (::aidl::android::hardware::automotive::evs::CameraParam in_id, int32_t in_value,
+ std::vector<int32_t>* _aidl_return),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, setPrimaryClient, (), (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, unsetPrimaryClient, (), (override));
+
+ bool mStreamStarted = false;
+ bool mStreamStopped = false;
+ bool mPreStartCalled = false;
+ bool mPostStartCalled = false;
+ bool mPreStopCalled = false;
+ bool mPostStopCalled = false;
+};
+
+class MockEvsCameraStream : public evs::IEvsCameraStream {
+ MOCK_METHOD(::ndk::SpAIBinder, asBinder, (), (override));
+ MOCK_METHOD(bool, isRemote, (), (override));
+ MOCK_METHOD(
+ ::ndk::ScopedAStatus, deliverFrame,
+ (const std::vector<::aidl::android::hardware::automotive::evs::BufferDesc>& in_buffer),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, notify,
+ (const ::aidl::android::hardware::automotive::evs::EvsEventDesc& in_event),
+ (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getInterfaceVersion, (int32_t * _aidl_return), (override));
+ MOCK_METHOD(::ndk::ScopedAStatus, getInterfaceHash, (std::string * _aidl_return), (override));
+};
+
+using StreamState = EvsCameraForTest::StreamState;
+
+TEST(EvsCameraStateTest, StateChangeHooks) {
+ auto evsCam = ndk::SharedRefBase::make<EvsCameraForTest>();
+ auto mockStream = ndk::SharedRefBase::make<MockEvsCameraStream>();
+ EXPECT_FALSE(evsCam->mPreStartCalled);
+ EXPECT_FALSE(evsCam->mPostStartCalled);
+ EXPECT_FALSE(evsCam->mPreStopCalled);
+ EXPECT_FALSE(evsCam->mPostStopCalled);
+ EXPECT_FALSE(evsCam->mStreamStarted);
+ EXPECT_FALSE(evsCam->mStreamStopped);
+ EXPECT_EQ(evsCam->mStreamState, StreamState::STOPPED);
+ evsCam->startVideoStream(mockStream);
+
+ EXPECT_TRUE(evsCam->mPreStartCalled);
+ EXPECT_TRUE(evsCam->mPostStartCalled);
+ EXPECT_FALSE(evsCam->mPreStopCalled);
+ EXPECT_FALSE(evsCam->mPostStopCalled);
+ EXPECT_TRUE(evsCam->mStreamStarted);
+ EXPECT_FALSE(evsCam->mStreamStopped);
+ EXPECT_EQ(evsCam->mStreamState, StreamState::RUNNING);
+ evsCam->stopVideoStream();
+
+ EXPECT_TRUE(evsCam->mPreStartCalled);
+ EXPECT_TRUE(evsCam->mPostStartCalled);
+ EXPECT_TRUE(evsCam->mPreStopCalled);
+ EXPECT_TRUE(evsCam->mPostStopCalled);
+ EXPECT_TRUE(evsCam->mStreamStarted);
+ EXPECT_TRUE(evsCam->mStreamStopped);
+ EXPECT_EQ(evsCam->mStreamState, StreamState::STOPPED);
+
+ evsCam->shutdown();
+ EXPECT_EQ(evsCam->mStreamState, StreamState::DEAD);
+}
+
+} // namespace aidl::android::hardware::automotive::evs::implementation
diff --git a/automotive/remoteaccess/Android.bp b/automotive/remoteaccess/Android.bp
index 7cd6f60..e1e9041 100644
--- a/automotive/remoteaccess/Android.bp
+++ b/automotive/remoteaccess/Android.bp
@@ -42,6 +42,5 @@
imports: [],
},
],
- frozen: true,
-
+ frozen: false,
}
diff --git a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
index b0935c2..ccfa22d 100644
--- a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
@@ -40,4 +40,10 @@
void setRemoteTaskCallback(android.hardware.automotive.remoteaccess.IRemoteTaskCallback callback);
void clearRemoteTaskCallback();
void notifyApStateChange(in android.hardware.automotive.remoteaccess.ApState state);
+ boolean isTaskScheduleSupported();
+ void scheduleTask(in android.hardware.automotive.remoteaccess.ScheduleInfo scheduleInfo);
+ void unscheduleTask(String clientId, String scheduleId);
+ void unscheduleAllTasks(String clientId);
+ boolean isTaskScheduled(String clientId, String scheduleId);
+ List<android.hardware.automotive.remoteaccess.ScheduleInfo> getAllScheduledTasks(String clientId);
}
diff --git a/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
new file mode 100644
index 0000000..a929e10
--- /dev/null
+++ b/automotive/remoteaccess/aidl_api/android.hardware.automotive.remoteaccess/current/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.remoteaccess;
+@JavaDerive(equals=true, toString=true) @VintfStability
+parcelable ScheduleInfo {
+ String clientId;
+ String scheduleId;
+ byte[] taskData;
+ int count;
+ long startTimeInEpochSeconds;
+ long periodicInSeconds;
+}
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
index 0f4125f..4912651 100644
--- a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/IRemoteAccess.aidl
@@ -18,6 +18,7 @@
import android.hardware.automotive.remoteaccess.ApState;
import android.hardware.automotive.remoteaccess.IRemoteTaskCallback;
+import android.hardware.automotive.remoteaccess.ScheduleInfo;
/**
* Interface representing a remote wakeup client.
@@ -96,4 +97,69 @@
* <p>If {@code isWakeupRequired} is false, it must not try to wake up AP.
*/
void notifyApStateChange(in ApState state);
+
+ /**
+ * Returns whether task scheduling is supported.
+ *
+ * <p>If this returns {@code true}, user may use {@link scheduleTask} to schedule a task to be
+ * executed at a later time. If the device is off when the task is scheduled to be executed,
+ * the device will be woken up to execute the task.
+ *
+ * @return {@code true} if serverless remote task scheduling is supported.
+ */
+ boolean isTaskScheduleSupported();
+
+ /**
+ * Schedules a task to be executed later even when the vehicle is off.
+ *
+ * <p>If {@link isTaskScheduleSupported} returns {@code false}. This is no-op.
+ *
+ * <p>This sends a scheduled task message to a device external to Android so that the device
+ * can wake up Android and deliver the task through {@link IRemoteTaskCallback}.
+ *
+ * <p>Note that the scheduled task execution is on a best-effort basis. Multiple situations
+ * might cause the task not to execute successfully:
+ *
+ * <ul>
+ * <li>The vehicle is low on battery and the other device decides not to wake up Android.
+ * <li>User turns off vehicle while the task is executing.
+ * <li>The task logic itself fails.
+ *
+ * <p>Must return {@code EX_ILLEGAL_ARGUMENT} if a pending schedule with the same
+ * {@code scheduleId} for this client exists.
+ */
+ void scheduleTask(in ScheduleInfo scheduleInfo);
+
+ /**
+ * Unschedules a scheduled task.
+ *
+ * <p>If {@link isTaskScheduleSupported} returns {@code false}. This is no-op.
+ *
+ * <p>Does nothing if a pending schedule with {@code clientId} and {@code scheduleId} does not
+ * exist.
+ */
+ void unscheduleTask(String clientId, String scheduleId);
+
+ /**
+ * Unschedules all scheduled tasks for the client.
+ *
+ * <p>If {@link isTaskScheduleSupported} returns {@code false}. This is no-op.
+ */
+ void unscheduleAllTasks(String clientId);
+
+ /**
+ * Returns whether the specified task is scheduled.
+ *
+ * <p>If {@link isTaskScheduleSupported} returns {@code false}, This must return {@code false}.
+ */
+ boolean isTaskScheduled(String clientId, String scheduleId);
+
+ /**
+ * Gets all pending scheduled tasks for the client.
+ *
+ * <p>If {@link isTaskScheduleSupported} returns {@code false}. This must return empty array.
+ *
+ * <p>The finished scheduled tasks will not be included.
+ */
+ List<ScheduleInfo> getAllScheduledTasks(String clientId);
}
diff --git a/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
new file mode 100644
index 0000000..cf1437b
--- /dev/null
+++ b/automotive/remoteaccess/android/hardware/automotive/remoteaccess/ScheduleInfo.aidl
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.remoteaccess;
+
+@VintfStability
+@JavaDerive(equals=true, toString=true)
+parcelable ScheduleInfo {
+ /**
+ * The ID used to identify the client this schedule is for. This must be one of the
+ * preconfigured remote access serverless client ID defined in car service resource
+ * {@code R.xml.remote_access_serverless_client_map}.
+ */
+ String clientId;
+ /**
+ * A unique scheduling ID (among the same client). Adding a new schedule info with a duplicate
+ * scheduleId will return {@code EX_ILLEGAL_ARGUMENT}.
+ */
+ String scheduleId;
+ /**
+ * The opaque task data that will be sent back to the remote task client app when the task is
+ * executed. It is not interpreted/parsed by the Android system.
+ */
+ byte[] taskData;
+ /**
+ * How many times this task will be executed. 0 means infinite.
+ *
+ * <p>This must be >= 0.
+ */
+ int count;
+ /**
+ * The start time in epoch seconds.
+ *
+ * <p>The external device issuing remote task must have a clock synced with the
+ * {@code System.currentTimeMillis()} used in Android system.
+ *
+ * <p>Optionally, the VHAL property {@code EPOCH_TIME} can be used to sync the time.
+ *
+ * <p>This must be >= 0.
+ */
+ long startTimeInEpochSeconds;
+ /**
+ * The interval (in seconds) between scheduled task execution.
+ *
+ * <p>This must be >=0. This is not useful when {@code count} is 1. If this is 0,
+ * The tasks will be delivered multiple times with no interval in between.
+ */
+ long periodicInSeconds;
+}
diff --git a/automotive/remoteaccess/hal/default/Android.bp b/automotive/remoteaccess/hal/default/Android.bp
index 48a7309..97ed2c1 100644
--- a/automotive/remoteaccess/hal/default/Android.bp
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -48,7 +48,7 @@
}
cc_binary {
- name: "android.hardware.automotive.remoteaccess@V1-default-service",
+ name: "android.hardware.automotive.remoteaccess@V2-default-service",
defaults: ["remote-access-hal-defaults"],
vintf_fragments: ["remoteaccess-default-service.xml"],
init_rc: ["remoteaccess-default-service.rc"],
@@ -58,7 +58,7 @@
}
cc_binary {
- name: "android.hardware.automotive.remoteaccess@V1-tcu-test-service",
+ name: "android.hardware.automotive.remoteaccess@V2-tcu-test-service",
defaults: ["remote-access-hal-defaults"],
vintf_fragments: ["remoteaccess-default-service.xml"],
init_rc: ["remoteaccess-tcu-test-service.rc"],
@@ -77,7 +77,7 @@
"src/RemoteAccessService.cpp",
],
whole_static_libs: [
- "android.hardware.automotive.remoteaccess-V1-ndk",
+ "android.hardware.automotive.remoteaccess-V2-ndk",
"wakeup_client_protos",
"libvhalclient",
],
@@ -99,7 +99,7 @@
}
cc_fuzz {
- name: "android.hardware.automotive.remoteaccess@V1-default-service.aidl_fuzzer",
+ name: "android.hardware.automotive.remoteaccess@V2-default-service.aidl_fuzzer",
srcs: ["fuzzer/fuzzer.cpp"],
whole_static_libs: [
"RemoteAccessService",
diff --git a/automotive/remoteaccess/hal/default/include/RemoteAccessService.h b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
index b18986a..1fc4037 100644
--- a/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
+++ b/automotive/remoteaccess/hal/default/include/RemoteAccessService.h
@@ -21,6 +21,7 @@
#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteAccess.h>
#include <aidl/android/hardware/automotive/remoteaccess/BnRemoteTaskCallback.h>
#include <aidl/android/hardware/automotive/remoteaccess/IRemoteTaskCallback.h>
+#include <aidl/android/hardware/automotive/remoteaccess/ScheduleInfo.h>
#include <android-base/thread_annotations.h>
#include <android/binder_auto_utils.h>
#include <utils/SystemClock.h>
@@ -78,6 +79,25 @@
ndk::ScopedAStatus notifyApStateChange(
const aidl::android::hardware::automotive::remoteaccess::ApState& newState) override;
+ ndk::ScopedAStatus isTaskScheduleSupported(bool* out) override;
+
+ ndk::ScopedAStatus scheduleTask(
+ const aidl::android::hardware::automotive::remoteaccess::ScheduleInfo& scheduleInfo)
+ override;
+
+ ndk::ScopedAStatus unscheduleTask(const std::string& clientId,
+ const std::string& scheduleId) override;
+
+ ndk::ScopedAStatus unscheduleAllTasks(const std::string& clientId) override;
+
+ ndk::ScopedAStatus isTaskScheduled(const std::string& clientId, const std::string& scheduleId,
+ bool* out) override;
+
+ ndk::ScopedAStatus getAllScheduledTasks(
+ const std::string& clientId,
+ std::vector<aidl::android::hardware::automotive::remoteaccess::ScheduleInfo>* out)
+ override;
+
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc b/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
index b7a9cdc..c9b282c 100644
--- a/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
+++ b/automotive/remoteaccess/hal/default/remoteaccess-default-service.rc
@@ -1,4 +1,4 @@
-service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-default-service
+service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V2-default-service
class hal
user vehicle_network
group system inet
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml b/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
index d050a1b..44ac309 100644
--- a/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
+++ b/automotive/remoteaccess/hal/default/remoteaccess-default-service.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.automotive.remoteaccess</name>
- <version>1</version>
+ <version>2</version>
<fqname>IRemoteAccess/default</fqname>
</hal>
</manifest>
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
index 59315eb..19faaf4 100644
--- a/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
+++ b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service.rc
@@ -1,4 +1,4 @@
-service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-tcu-test-service
+service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V2-tcu-test-service
class hal
user vehicle_network
group system inet
diff --git a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
index 5081ac0..7721bf4 100644
--- a/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
+++ b/automotive/remoteaccess/hal/default/src/RemoteAccessService.cpp
@@ -39,6 +39,7 @@
using ::aidl::android::hardware::automotive::remoteaccess::ApState;
using ::aidl::android::hardware::automotive::remoteaccess::IRemoteTaskCallback;
+using ::aidl::android::hardware::automotive::remoteaccess::ScheduleInfo;
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
using ::android::base::Error;
using ::android::base::ParseInt;
@@ -313,6 +314,41 @@
return ScopedAStatus::ok();
}
+ScopedAStatus RemoteAccessService::isTaskScheduleSupported([[maybe_unused]] bool* out) {
+ // TODO(b/297271235): implement this.
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::scheduleTask([[maybe_unused]] const ScheduleInfo& scheduleInfo) {
+ // TODO(b/297271235): implement this.
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::unscheduleTask([[maybe_unused]] const std::string& clientId,
+ [[maybe_unused]] const std::string& scheduleId) {
+ // TODO(b/297271235): implement this.
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::unscheduleAllTasks(
+ [[maybe_unused]] const std::string& clientId) {
+ // TODO(b/297271235): implement this.
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::isTaskScheduled([[maybe_unused]] const std::string& clientId,
+ [[maybe_unused]] const std::string& scheduleId,
+ [[maybe_unused]] bool* out) {
+ // TODO(b/297271235): implement this.
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteAccessService::getAllScheduledTasks(const std::string& clientId,
+ std::vector<ScheduleInfo>* out) {
+ // TODO(b/297271235): implement this.
+ return ScopedAStatus::ok();
+}
+
bool RemoteAccessService::checkDumpPermission() {
uid_t uid = AIBinder_getCallingUid();
return uid == AID_ROOT || uid == AID_SHELL || uid == AID_SYSTEM;
diff --git a/automotive/remoteaccess/test_grpc_server/README.md b/automotive/remoteaccess/test_grpc_server/README.md
index af3d54a..d2b6bbe 100644
--- a/automotive/remoteaccess/test_grpc_server/README.md
+++ b/automotive/remoteaccess/test_grpc_server/README.md
@@ -141,7 +141,7 @@
* The android lunch target: sdk_car_x86_64-userdebug and
cf_x86_64_auto-userdebug already contains the default remote access HAL. For
other lunch target, you can add the default remote access HAL by adding
- 'android.hardware.automotive.remoteaccess@V1-default-service' to
+ 'android.hardware.automotive.remoteaccess@V2-default-service' to
'PRODUCT_PACKAGES' variable in mk file, see `device/generic/car/common/car.mk`
as example.
diff --git a/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp b/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
index 98834f5..4c4cc70 100644
--- a/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
+++ b/automotive/sv/1.0/default/tests/fuzzer/AutomotiveSvV1_0Fuzzer.cpp
@@ -41,35 +41,32 @@
void SurroundViewFuzzer::invoke2dSessionAPI() {
sp<ISurroundView2dSession> surroundView2dSession;
+ sp<SurroundViewStream> handler;
+ mSurroundViewService->start2dSession(
+ [&surroundView2dSession](const sp<ISurroundView2dSession>& session, SvResult result) {
+ if (result == SvResult::OK) {
+ surroundView2dSession = session;
+ }
+ });
+
+ if (surroundView2dSession && !mIs2dStreamStarted) {
+ handler = sp<SurroundViewStream>::make(surroundView2dSession);
+ if (surroundView2dSession->startStream(handler) == SvResult::OK) {
+ mIs2dStreamStarted = true;
+ }
+ }
while (mFuzzedDataProvider.remaining_bytes() > 0) {
auto surroundView2dFunc = mFuzzedDataProvider.PickValueInArray<
const std::function<void()>>({
[&]() {
- mSurroundViewService->start2dSession(
- [&surroundView2dSession](const sp<ISurroundView2dSession>& session,
- SvResult result) {
- if (result == SvResult::OK) {
- surroundView2dSession = session;
- }
- });
- },
- [&]() {
- if (surroundView2dSession) {
- sp<SurroundViewStream> handler =
- sp<SurroundViewStream>::make(surroundView2dSession);
- surroundView2dSession->startStream(handler);
- mIs2dStreamStarted = true;
- }
- },
- [&]() {
if (surroundView2dSession) {
surroundView2dSession->get2dMappingInfo(
[]([[maybe_unused]] Sv2dMappingInfo info) {});
}
},
[&]() {
- if (surroundView2dSession) {
+ if (surroundView2dSession && mIs2dStreamStarted) {
Sv2dConfig config;
config.width = mFuzzedDataProvider.ConsumeIntegralInRange<uint32_t>(
kMinConfigDimension, kMaxConfigDimension);
@@ -149,8 +146,11 @@
}
},
[&]() {
- mSurroundViewService->stop2dSession(
+ SvResult result = mSurroundViewService->stop2dSession(
mFuzzedDataProvider.ConsumeBool() ? surroundView2dSession : nullptr);
+ if (result == SvResult::OK) {
+ mIs2dStreamStarted = false;
+ }
},
});
surroundView2dFunc();
@@ -159,31 +159,40 @@
if (surroundView2dSession && mIs2dStreamStarted) {
surroundView2dSession->stopStream();
}
+
+ if (surroundView2dSession) {
+ mSurroundViewService->stop2dSession(surroundView2dSession);
+ }
}
void SurroundViewFuzzer::invoke3dSessionAPI() {
sp<ISurroundView3dSession> surroundView3dSession;
+ sp<SurroundViewStream> handler;
+ mSurroundViewService->start3dSession(
+ [&surroundView3dSession](const sp<ISurroundView3dSession>& session, SvResult result) {
+ if (result == SvResult::OK) {
+ surroundView3dSession = session;
+ }
+ });
+
+ const size_t numViews = mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(1, kMaxViews);
+ std::vector<View3d> views(numViews);
+ for (size_t i = 0; i < numViews; ++i) {
+ views[i].viewId = mFuzzedDataProvider.ConsumeIntegral<uint32_t>();
+ }
+ surroundView3dSession->setViews(views);
+
+ if (surroundView3dSession) {
+ handler = sp<SurroundViewStream>::make(surroundView3dSession);
+
+ if (surroundView3dSession->startStream(handler) == SvResult::OK) {
+ mIs3dStreamStarted = true;
+ }
+ }
while (mFuzzedDataProvider.remaining_bytes() > 0) {
auto surroundView3dFunc = mFuzzedDataProvider.PickValueInArray<
const std::function<void()>>({
[&]() {
- mSurroundViewService->start3dSession(
- [&surroundView3dSession](const sp<ISurroundView3dSession>& session,
- SvResult result) {
- if (result == SvResult::OK) {
- surroundView3dSession = session;
- }
- });
- },
- [&]() {
- if (surroundView3dSession) {
- sp<SurroundViewStream> handler =
- sp<SurroundViewStream>::make(surroundView3dSession);
- surroundView3dSession->startStream(handler);
- mIs3dStreamStarted = true;
- }
- },
- [&]() {
if (surroundView3dSession) {
const size_t numViews =
mFuzzedDataProvider.ConsumeIntegralInRange<size_t>(1, kMaxViews);
@@ -195,7 +204,7 @@
}
},
[&]() {
- if (surroundView3dSession) {
+ if (surroundView3dSession && mIs3dStreamStarted) {
Sv3dConfig config;
config.width = mFuzzedDataProvider.ConsumeIntegralInRange<uint32_t>(
kMinConfigDimension, kMaxConfigDimension);
@@ -306,8 +315,11 @@
}
},
[&]() {
- mSurroundViewService->stop3dSession(
+ SvResult result = mSurroundViewService->stop3dSession(
mFuzzedDataProvider.ConsumeBool() ? surroundView3dSession : nullptr);
+ if (result == SvResult::OK) {
+ mIs3dStreamStarted = false;
+ }
},
});
surroundView3dFunc();
@@ -315,6 +327,10 @@
if (surroundView3dSession && mIs3dStreamStarted) {
surroundView3dSession->stopStream();
}
+
+ if (surroundView3dSession) {
+ mSurroundViewService->stop3dSession(surroundView3dSession);
+ }
}
void SurroundViewFuzzer::process() {
diff --git a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
index 796c08f..8a085e5 100644
--- a/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
+++ b/automotive/vehicle/2.0/default/tests/fuzzer/VehicleManager_fuzzer.cpp
@@ -161,10 +161,13 @@
hidl_string debugOption = mFuzzedDataProvider->PickValueInArray(
{"--help", "--list", "--get", "--set", "", "invalid"});
hidl_handle fd = {};
- fd.setTo(native_handle_create(/*numFds=*/1, /*numInts=*/0), /*shouldOwn=*/true);
+
+ native_handle_t* rawHandle = native_handle_create(/*numFds=*/1, /*numInts=*/0);
+ fd.setTo(native_handle_clone(rawHandle), /*shouldOwn=*/true);
mManager->debug(fd, {});
mManager->debug(fd, {debugOption});
+ native_handle_delete(rawHandle);
}
void VehicleHalManagerFuzzer::invokePropConfigs() {
diff --git a/automotive/vehicle/OWNERS b/automotive/vehicle/OWNERS
index 429ec39..d6969e5 100644
--- a/automotive/vehicle/OWNERS
+++ b/automotive/vehicle/OWNERS
@@ -1,3 +1,2 @@
ericjeong@google.com
-keunyoung@google.com
shanyu@google.com
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index d0c6e83..92c2707 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -247,6 +247,7 @@
{VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess::READ},
{VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyAccess::WRITE},
{VehicleProperty::VEHICLE_IN_USE, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyAccess::WRITE},
{VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess::READ},
{VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index 48532c9..e1bdf7d 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -247,6 +247,7 @@
{VehicleProperty::SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode::STATIC},
{VehicleProperty::SHUTDOWN_REQUEST, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::VEHICLE_IN_USE, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index 758670d..b5c3de9 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -239,6 +239,7 @@
Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyAccess.WRITE),
Map.entry(VehicleProperty.VEHICLE_IN_USE, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.CLUSTER_HEARTBEAT, VehiclePropertyAccess.WRITE),
Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index 29069f8..0f126e7 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -239,6 +239,7 @@
Map.entry(VehicleProperty.SUPPORTED_PROPERTY_IDS, VehiclePropertyChangeMode.STATIC),
Map.entry(VehicleProperty.SHUTDOWN_REQUEST, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.VEHICLE_IN_USE, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.CLUSTER_HEARTBEAT, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
diff --git a/automotive/vehicle/aidl/impl/README.md b/automotive/vehicle/aidl/impl/README.md
index 121ffd1..2cd3a3e 100644
--- a/automotive/vehicle/aidl/impl/README.md
+++ b/automotive/vehicle/aidl/impl/README.md
@@ -46,7 +46,7 @@
use this library, along with their own implementation for `IVehicleHardware`
interface.
-Also defines a binary `android.hardware.automotive.vehicle@V1-default-service`
+Also defines a binary `android.hardware.automotive.vehicle@V3-default-service`
which is the reference VHAL implementation. It implements `IVehicle.aidl`
interface. It uses `DefaultVehicleHal`, along with `FakeVehicleHardware`
(in fake_impl). It simulates the vehicle bus interaction by using an
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index b9f784b..4a16bf7 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -3621,6 +3621,21 @@
"property": "VehicleProperty::CLUSTER_NAVIGATION_STATE"
},
{
+ "property": "VehicleProperty::CLUSTER_HEARTBEAT",
+ "configArray": [
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 2,
+ 0,
+ 0,
+ 16
+ ],
+ "comment": "configArray specifies it consists of int64[2] and byte[16]."
+ },
+ {
"property": "VehicleProperty::GENERAL_SAFETY_REGULATION_COMPLIANCE_REQUIREMENT",
"defaultValue": {
"int32Values": [
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index f130fa4..e8da43a 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -99,12 +99,17 @@
const std::shared_ptr<VehiclePropValuePool> mValuePool;
const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
+ const std::string mDefaultConfigDir;
+ const std::string mOverrideConfigDir;
+
ValueResultType getValue(
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
VhalResult<void> setValue(
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+ bool UseOverrideConfigDir();
+
private:
// Expose private methods to unit test.
friend class FakeVehicleHardwareTestHelper;
@@ -156,8 +161,6 @@
aidl::android::hardware::automotive::vehicle::SetValueRequest>
mPendingSetValueRequests;
- const std::string mDefaultConfigDir;
- const std::string mOverrideConfigDir;
const bool mForceOverride;
bool mAddExtraTestVendorConfigs;
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 82c3ea0..13c48c6 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -39,7 +39,6 @@
#include <dirent.h>
#include <inttypes.h>
#include <sys/types.h>
-#include <fstream>
#include <regex>
#include <unordered_set>
#include <vector>
@@ -206,9 +205,10 @@
// Create a separate instance for each individual zone
VehiclePropValue prop = {
+ .timestamp = elapsedRealtimeNano(),
.areaId = curArea,
.prop = propId,
- .timestamp = elapsedRealtimeNano(),
+ .value = {},
};
if (config.initialAreaValues.empty()) {
@@ -241,6 +241,8 @@
std::string overrideConfigDir, bool forceOverride)
: mValuePool(std::make_unique<VehiclePropValuePool>()),
mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
+ mDefaultConfigDir(defaultConfigDir),
+ mOverrideConfigDir(overrideConfigDir),
mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
mFakeUserHal(new FakeUserHal(mValuePool)),
mRecurrentTimer(new RecurrentTimer()),
@@ -248,8 +250,6 @@
[this](const VehiclePropValue& value) { eventFromVehicleBus(value); })),
mPendingGetValueRequests(this),
mPendingSetValueRequests(this),
- mDefaultConfigDir(defaultConfigDir),
- mOverrideConfigDir(overrideConfigDir),
mForceOverride(forceOverride) {
init();
}
@@ -260,11 +260,15 @@
mGeneratorHub.reset();
}
+bool FakeVehicleHardware::UseOverrideConfigDir() {
+ return mForceOverride ||
+ android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false);
+}
+
std::unordered_map<int32_t, ConfigDeclaration> FakeVehicleHardware::loadConfigDeclarations() {
std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
- if (mForceOverride ||
- android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false)) {
+ if (UseOverrideConfigDir()) {
loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId);
}
return configsByPropId;
@@ -1035,7 +1039,7 @@
<< StringPrintf("failed to get special value: %d, error: %s", value.prop,
getErrorMsg(result).c_str());
} else {
- return std::move(result);
+ return result;
}
}
@@ -1050,7 +1054,7 @@
}
}
- return std::move(readResult);
+ return readResult;
}
DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
@@ -1087,9 +1091,11 @@
} else if (EqualsIgnoreCase(option, "--genTestVendorConfigs")) {
mAddExtraTestVendorConfigs = true;
result.refreshPropertyConfigs = true;
+ result.buffer = "successfully generated vendor configs";
} else if (EqualsIgnoreCase(option, "--restoreVendorConfigs")) {
mAddExtraTestVendorConfigs = false;
result.refreshPropertyConfigs = true;
+ result.buffer = "successfully restored vendor configs";
} else {
result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
}
@@ -1425,9 +1431,9 @@
VehiclePropValue FakeVehicleHardware::createHwInputKeyProp(VehicleHwKeyInputAction action,
int32_t keyCode, int32_t targetDisplay) {
VehiclePropValue value = {
- .prop = toInt(VehicleProperty::HW_KEY_INPUT),
- .areaId = 0,
.timestamp = elapsedRealtimeNano(),
+ .areaId = 0,
+ .prop = toInt(VehicleProperty::HW_KEY_INPUT),
.status = VehiclePropertyStatus::AVAILABLE,
.value.int32Values = {toInt(action), keyCode, targetDisplay},
};
@@ -1437,9 +1443,9 @@
VehiclePropValue FakeVehicleHardware::createHwKeyInputV2Prop(int32_t area, int32_t targetDisplay,
int32_t keyCode, int32_t action,
int32_t repeatCount) {
- VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
+ VehiclePropValue value = {.timestamp = elapsedRealtimeNano(),
.areaId = area,
- .timestamp = elapsedRealtimeNano(),
+ .prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
.status = VehiclePropertyStatus::AVAILABLE,
.value.int32Values = {targetDisplay, keyCode, action, repeatCount},
.value.int64Values = {elapsedRealtimeNano()}};
@@ -1477,9 +1483,9 @@
floatValues.push_back(size[i]);
}
- VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_MOTION_INPUT),
+ VehiclePropValue value = {.timestamp = elapsedRealtimeNano(),
.areaId = area,
- .timestamp = elapsedRealtimeNano(),
+ .prop = toInt(VehicleProperty::HW_MOTION_INPUT),
.status = VehiclePropertyStatus::AVAILABLE,
.value.int32Values = intValues,
.value.floatValues = floatValues,
@@ -1548,8 +1554,9 @@
std::string FakeVehicleHardware::dumpOnePropertyById(int32_t propId, int32_t areaId) {
VehiclePropValue value = {
- .prop = propId,
.areaId = areaId,
+ .prop = propId,
+ .value = {},
};
bool isSpecialValue = false;
auto result = maybeGetSpecialValue(value, &isSpecialValue);
@@ -1620,12 +1627,12 @@
while (*index < options.size()) {
std::string option = options[*index];
if (SET_PROP_OPTIONS.find(option) != SET_PROP_OPTIONS.end()) {
- return std::move(values);
+ return values;
}
values.push_back(option);
(*index)++;
}
- return std::move(values);
+ return values;
}
Result<VehiclePropValue> FakeVehicleHardware::parsePropOptions(
@@ -1934,8 +1941,9 @@
// Refresh the property value. In real implementation, this should poll the latest value
// from vehicle bus. Here, we are just refreshing the existing value with a new timestamp.
auto result = getValue(VehiclePropValue{
- .prop = propId,
.areaId = areaId,
+ .prop = propId,
+ .value = {},
});
if (!result.ok()) {
// Failed to read current value, skip refreshing.
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index e740da7..ddd620e 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -82,6 +82,10 @@
bool waitForConnected(std::chrono::milliseconds waitTime);
+ protected:
+ std::shared_mutex mCallbackMutex;
+ std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
+
private:
void ValuePollingLoop();
@@ -90,8 +94,6 @@
std::unique_ptr<proto::VehicleServer::Stub> mGrpcStub;
std::thread mValuePollingThread;
- std::shared_mutex mCallbackMutex;
- std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
std::unique_ptr<const PropertySetErrorCallback> mOnSetErr;
std::mutex mShutdownMutex;
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index 4feea79..c29345f 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -19,7 +19,7 @@
}
cc_binary {
- name: "android.hardware.automotive.vehicle@V1-default-service",
+ name: "android.hardware.automotive.vehicle@V3-default-service",
vendor: true,
defaults: [
"FakeVehicleHardwareDefaults",
@@ -68,7 +68,7 @@
}
cc_fuzz {
- name: "android.hardware.automotive.vehicle@V1-default-service_fuzzer",
+ name: "android.hardware.automotive.vehicle-default-service_fuzzer",
vendor: true,
defaults: [
"FakeVehicleHardwareDefaults",
diff --git a/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc b/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc
index 19267cd..9fa7b98 100644
--- a/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc
+++ b/automotive/vehicle/aidl/impl/vhal/vhal-default-service.rc
@@ -1,4 +1,4 @@
-service vendor.vehicle-hal-default /vendor/bin/hw/android.hardware.automotive.vehicle@V1-default-service
+service vendor.vehicle-hal-default /vendor/bin/hw/android.hardware.automotive.vehicle@V3-default-service
class early_hal
user vehicle_network
group system inet
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index ba75e7b..231186f 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -245,6 +245,7 @@
SUPPORTED_PROPERTY_IDS = (((0x0F48 + 0x10000000) + 0x01000000) + 0x00410000) /* 289476424 */,
SHUTDOWN_REQUEST = (((0x0F49 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289410889 */,
VEHICLE_IN_USE = (((0x0F4A + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313738 */,
+ CLUSTER_HEARTBEAT = (((0x0F4B + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.MIXED) /* 299896651 */,
AUTOMATIC_EMERGENCY_BRAKING_ENABLED = (((0x1000 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313920 */,
AUTOMATIC_EMERGENCY_BRAKING_STATE = (((0x1001 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411073 */,
FORWARD_COLLISION_WARNING_ENABLED = (((0x1002 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313922 */,
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 7d88810..545df4b 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -4487,6 +4487,20 @@
VEHICLE_IN_USE =
0x0F4A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+ /**
+ * Sends the heartbeat signal to ClusterOS.
+ *
+ * int64[0]: epochTimeNs
+ * int64[1]: the visibility of ClusterUI, 0 - invisible, 1 - visible
+ * bytes: the app specific metadata, this can be empty when ClusterHomeService use the heartbeat
+ * to deliver the change of the visibility.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.WRITE
+ */
+ CLUSTER_HEARTBEAT =
+ 0x0F4B + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.MIXED,
+
/***********************************************************************************************
* Start of ADAS Properties
*
diff --git a/automotive/vehicle/proto/Android.bp b/automotive/vehicle/proto/Android.bp
index 683f128..e7dabcf 100644
--- a/automotive/vehicle/proto/Android.bp
+++ b/automotive/vehicle/proto/Android.bp
@@ -27,6 +27,7 @@
visibility: [
"//hardware/interfaces/automotive/vehicle:__subpackages__",
"//device/generic/car/emulator:__subpackages__",
+ "//system/software_defined_vehicle/core_services:__subpackages__",
],
vendor: true,
host_supported: true,
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 8bcad1e..6e6d05c 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -865,6 +865,12 @@
VehicleArea::GLOBAL, VehiclePropertyType::INT32);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyClusterHeartbeatConfig) {
+ verifyProperty(VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyAccess::WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::GLOBAL, VehiclePropertyType::MIXED);
+}
+
std::vector<ServiceDescriptor> getDescriptors() {
std::vector<ServiceDescriptor> descriptors;
for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {
diff --git a/biometrics/common/util/include/util/Util.h b/biometrics/common/util/include/util/Util.h
index da19dc6..efd66bc 100644
--- a/biometrics/common/util/include/util/Util.h
+++ b/biometrics/common/util/include/util/Util.h
@@ -23,6 +23,9 @@
#include <thread>
#include <vector>
+#include <android-base/parseint.h>
+using ::android::base::ParseInt;
+
namespace aidl::android::hardware::biometrics {
#define SLEEP_MS(x) \
@@ -64,6 +67,87 @@
std::sregex_token_iterator());
return parts;
}
+
+ // Returns a vector of integers for the string separated by comma,
+ // Empty vector is returned if there is any parsing error
+ static std::vector<int32_t> parseIntSequence(const std::string& str,
+ const std::string& sep = ",") {
+ std::vector<std::string> seqs = Util::split(str, sep);
+ std::vector<int32_t> res;
+
+ for (const auto& seq : seqs) {
+ int32_t val;
+ if (ParseInt(seq, &val)) {
+ res.push_back(val);
+ } else {
+ LOG(WARNING) << "Invalid int sequence:" + str + " seq:" + seq;
+ res.clear();
+ break;
+ }
+ }
+
+ return res;
+ }
+
+ // Parses a single enrollment stage string in the format of
+ // enroll_stage_spec: <duration>[-acquiredInfos]
+ // duration: integerInMs
+ // acquiredInfos: [info1,info2,...]
+ //
+ // Returns false if there is parsing error
+ //
+ static bool parseEnrollmentCaptureSingle(const std::string& str,
+ std::vector<std::vector<int32_t>>& res) {
+ std::vector<int32_t> defaultAcquiredInfo = {1};
+ bool aborted = true;
+
+ do {
+ std::smatch sms;
+ // Parses strings like "1000-[5,1]" or "500"
+ std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
+ if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
+ int32_t duration;
+ if (!ParseInt(sms.str(2), &duration)) break;
+ res.push_back({duration});
+ if (!sms.str(4).empty()) {
+ auto acqv = parseIntSequence(sms.str(4));
+ if (acqv.empty()) break;
+ res.push_back(acqv);
+ } else
+ res.push_back(defaultAcquiredInfo);
+ aborted = false;
+ } while (0);
+
+ return !aborted;
+ }
+
+ // Parses enrollment string consisting of one or more stages in the formst of
+ // <enroll_stage_spec>[,enroll_stage_spec,...]
+ // Empty vector is returned in case of parsing error
+ static std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str) {
+ std::vector<std::vector<int32_t>> res;
+
+ std::string s(str);
+ s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
+ bool aborted = false;
+ std::smatch sms;
+ // Parses strings like "1000-[5,1],500,800-[6,5,1]"
+ // -------------- ----- ---------------
+ // into parts: A B C
+ while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
+ if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
+ aborted = true;
+ break;
+ }
+ s = sms.suffix();
+ }
+ if (aborted || s.length() != 0) {
+ res.clear();
+ LOG(ERROR) << "Failed to parse enrollment captures:" + str;
+ }
+
+ return res;
+ }
};
} // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.cpp b/biometrics/face/aidl/default/FakeFaceEngine.cpp
index 0f088f4..578231d 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.cpp
+++ b/biometrics/face/aidl/default/FakeFaceEngine.cpp
@@ -136,56 +136,127 @@
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();
+
+ auto vec2str = [](std::vector<AcquiredInfo> va) {
+ std::stringstream ss;
+ bool isFirst = true;
+ for (auto ac : va) {
+ if (!isFirst) ss << ",";
+ ss << std::to_string((int8_t)ac);
+ isFirst = false;
+ }
+ return ss.str();
+ };
+
+ // default behavior mimic face sensor in U
+ int64_t defaultAuthDuration = 500;
+ std::string defaultAcquiredInfo =
+ vec2str({AcquiredInfo::START, AcquiredInfo::FIRST_FRAME_RECEIVED});
+ if (!isEnrolled) {
+ std::vector<AcquiredInfo> v;
+ for (int i = 0; i < 56; i++) v.push_back(AcquiredInfo::NOT_DETECTED);
+ defaultAcquiredInfo += "," + vec2str(v);
+ defaultAuthDuration = 2100;
+ } else {
+ defaultAcquiredInfo += "," + vec2str({AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
+ AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
+ AcquiredInfo::GOOD, AcquiredInfo::GOOD});
+ }
+
+ int64_t now = Util::getSystemNanoTime();
+ int64_t duration =
+ FaceHalProperties::operation_authenticate_duration().value_or(defaultAuthDuration);
+ auto acquired =
+ FaceHalProperties::operation_authenticate_acquired().value_or(defaultAcquiredInfo);
+ auto acquiredInfos = Util::parseIntSequence(acquired);
+ int N = acquiredInfos.size();
+
+ if (N == 0) {
+ LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
return;
}
- cb->onAuthenticationSucceeded(id, {} /* hat */);
+ int i = 0;
+ do {
+ if (FaceHalProperties::lockout().value_or(false)) {
+ LOG(ERROR) << "Fail: lockout";
+ cb->onLockoutPermanent();
+ cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
+ return;
+ }
+
+ if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
+ LOG(ERROR) << "Fail: operation_authenticate_fails";
+ cb->onAuthenticationFailed();
+ return;
+ }
+
+ auto err = FaceHalProperties::operation_authenticate_error().value_or(0);
+ if (err != 0) {
+ LOG(ERROR) << "Fail: operation_authenticate_error";
+ auto ec = convertError(err);
+ cb->onError(ec.first, ec.second);
+ return; /* simply terminating current operation for any user inserted error,
+ revisit if tests need*/
+ }
+
+ if (shouldCancel(cancel)) {
+ LOG(ERROR) << "Fail: cancel";
+ cb->onError(Error::CANCELED, 0 /* vendorCode */);
+ return;
+ }
+
+ if (i < N) {
+ auto ac = convertAcquiredInfo(acquiredInfos[i]);
+ AuthenticationFrame frame;
+ frame.data.acquiredInfo = ac.first;
+ frame.data.vendorCode = ac.second;
+ cb->onAuthenticationFrame(frame);
+ LOG(INFO) << "AcquiredInfo:" << i << ": (" << (int)ac.first << "," << (int)ac.second
+ << ")";
+ i++;
+ }
+
+ SLEEP_MS(duration / N);
+ } while (!Util::hasElapsed(now, duration));
+
+ if (id > 0 && isEnrolled) {
+ cb->onAuthenticationSucceeded(id, {} /* hat */);
+ return;
+ } else {
+ LOG(ERROR) << "Fail: face not enrolled";
+ cb->onAuthenticationFailed();
+ cb->onError(Error::TIMEOUT, 0 /* vendorError*/);
+ return;
+ }
+}
+
+std::pair<AcquiredInfo, int32_t> FakeFaceEngine::convertAcquiredInfo(int32_t code) {
+ std::pair<AcquiredInfo, int32_t> res;
+ if (code > FACE_ACQUIRED_VENDOR_BASE) {
+ res.first = AcquiredInfo::VENDOR;
+ res.second = code - FACE_ACQUIRED_VENDOR_BASE;
+ } else {
+ res.first = (AcquiredInfo)code;
+ res.second = 0;
+ }
+ return res;
+}
+
+std::pair<Error, int32_t> FakeFaceEngine::convertError(int32_t code) {
+ std::pair<Error, int32_t> res;
+ if (code > FACE_ERROR_VENDOR_BASE) {
+ res.first = Error::VENDOR;
+ res.second = code - FACE_ERROR_VENDOR_BASE;
+ } else {
+ res.first = (Error)code;
+ res.second = 0;
+ }
+ return res;
}
void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
@@ -315,4 +386,4 @@
cb->onLockoutCleared();
}
-} // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.h b/biometrics/face/aidl/default/FakeFaceEngine.h
index eb99441..06dd396 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.h
+++ b/biometrics/face/aidl/default/FakeFaceEngine.h
@@ -62,6 +62,12 @@
void resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/);
std::mt19937 mRandom;
+
+ private:
+ static constexpr int32_t FACE_ACQUIRED_VENDOR_BASE = 1000;
+ static constexpr int32_t FACE_ERROR_VENDOR_BASE = 1000;
+ std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
+ std::pair<Error, int32_t> convertError(int32_t code);
};
} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/README.md b/biometrics/face/aidl/default/README.md
index 77bfe57..516a7aa 100644
--- a/biometrics/face/aidl/default/README.md
+++ b/biometrics/face/aidl/default/README.md
@@ -18,6 +18,7 @@
Face VHAL enabling is gated by the following two AND conditions:
1. The Face VHAL feature flag (as part of Trunk-development strategy) must be tured until the flags life-cycle ends.
2. The Face VHAL must be enabled via sysprop
+See adb commands below
##Getting Stared
@@ -47,8 +48,7 @@
$ adb shell setprop vendor.face.virtual.operation_authenticate_duration 800
$ adb shell setprop vendor.face.virtual.enrollment_hit 1
```
-Note: At the initial phase of the Face VHAL development, Face-on-camera simulation is not supported, hence
-the authentication immediately occurrs as soon as the authentication request arriving at VHAL.
+Refer to face.sysprop for full supported features of authentication, such as error and acquiredInfo insertion
## Enrollment via Setup
diff --git a/biometrics/face/aidl/default/face.sysprop b/biometrics/face/aidl/default/face.sysprop
index 6b0f37f..be32015 100644
--- a/biometrics/face/aidl/default/face.sysprop
+++ b/biometrics/face/aidl/default/face.sysprop
@@ -157,3 +157,22 @@
access: ReadWrite
api_name: "operation_authenticate_duration"
}
+
+# insert error for authenticate operations
+prop {
+ prop_name: "vendor.face.virtual.operation_authenticate_error"
+ type: Integer
+ scope: Internal
+ access: ReadWrite
+ api_name: "operation_authenticate_error"
+}
+
+# acquired info during authentication in format of sequence
+prop {
+ prop_name: "vendor.face.virtual.operation_authenticate_acquired"
+ type: String
+ scope: Internal
+ access: ReadWrite
+ api_name: "operation_authenticate_acquired"
+}
+
diff --git a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
index c8ad6b7..6897dc4 100644
--- a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
+++ b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
@@ -245,7 +245,7 @@
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_EQ(Error::TIMEOUT, mCallback->mError);
ASSERT_TRUE(mCallback->mAuthenticateFailed);
}
@@ -380,4 +380,4 @@
ASSERT_FALSE(mCallback->mAuthenticateFailed);
}
-} // namespace aidl::android::hardware::biometrics::face
\ No newline at end of file
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 54076c8..574570e 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -142,7 +142,7 @@
return true;
}
auto enrollmentId = std::stoi(parts[0]);
- auto progress = parseEnrollmentCapture(parts[1]);
+ auto progress = Util::parseEnrollmentCapture(parts[1]);
for (size_t i = 0; i < progress.size(); i += 2) {
auto left = (progress.size() - i) / 2 - 1;
auto duration = progress[i][0];
@@ -193,7 +193,7 @@
int64_t now = Util::getSystemNanoTime();
int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(10);
auto acquired = FingerprintHalProperties::operation_authenticate_acquired().value_or("1");
- auto acquiredInfos = parseIntSequence(acquired);
+ auto acquiredInfos = Util::parseIntSequence(acquired);
int N = acquiredInfos.size();
if (N == 0) {
@@ -271,7 +271,7 @@
FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
- auto acquiredInfos = parseIntSequence(acquired);
+ auto acquiredInfos = Util::parseIntSequence(acquired);
int N = acquiredInfos.size();
int64_t now = Util::getSystemNanoTime();
@@ -450,76 +450,6 @@
return SensorLocation();
}
-std::vector<int32_t> FakeFingerprintEngine::parseIntSequence(const std::string& str,
- const std::string& sep) {
- std::vector<std::string> seqs = Util::split(str, sep);
- std::vector<int32_t> res;
-
- for (const auto& seq : seqs) {
- int32_t val;
- if (ParseInt(seq, &val)) {
- res.push_back(val);
- } else {
- LOG(WARNING) << "Invalid int sequence:" + str;
- res.clear();
- break;
- }
- }
-
- return res;
-}
-
-bool FakeFingerprintEngine::parseEnrollmentCaptureSingle(const std::string& str,
- std::vector<std::vector<int32_t>>& res) {
- std::vector<int32_t> defaultAcquiredInfo = {(int32_t)AcquiredInfo::GOOD};
- bool aborted = true;
-
- do {
- std::smatch sms;
- // Parses strings like "1000-[5,1]" or "500"
- std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
- if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
- int32_t duration;
- if (!ParseInt(sms.str(2), &duration)) break;
- res.push_back({duration});
- if (!sms.str(4).empty()) {
- auto acqv = parseIntSequence(sms.str(4));
- if (acqv.empty()) break;
- res.push_back(acqv);
- } else
- res.push_back(defaultAcquiredInfo);
- aborted = false;
- } while (0);
-
- return !aborted;
-}
-
-std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
- const std::string& str) {
- std::vector<std::vector<int32_t>> res;
-
- std::string s(str);
- s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
- bool aborted = false;
- std::smatch sms;
- // Parses strings like "1000-[5,1],500,800-[6,5,1]"
- // ---------- --- -----------
- // into parts: A B C
- while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
- if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
- aborted = true;
- break;
- }
- s = sms.suffix();
- }
- if (aborted || s.length() != 0) {
- res.clear();
- LOG(ERROR) << "Failed to parse enrollment captures:" + str;
- }
-
- return res;
-}
-
std::pair<AcquiredInfo, int32_t> FakeFingerprintEngine::convertAcquiredInfo(int32_t code) {
std::pair<AcquiredInfo, int32_t> res;
if (code > FINGERPRINT_ACQUIRED_VENDOR_BASE) {
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 2450115..15d8360 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -68,10 +68,6 @@
virtual void fingerDownAction();
- std::vector<int32_t> parseIntSequence(const std::string& str, const std::string& sep = ",");
-
- std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str);
-
int32_t getLatency(const std::vector<std::optional<std::int32_t>>& latencyVec);
std::mt19937 mRandom;
@@ -110,8 +106,6 @@
static constexpr int32_t FINGERPRINT_ERROR_VENDOR_BASE = 1000;
std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
std::pair<Error, int32_t> convertError(int32_t code);
- bool parseEnrollmentCaptureSingle(const std::string& str,
- std::vector<std::vector<int32_t>>& res);
int32_t getRandomInRange(int32_t bound1, int32_t bound2);
bool checkSensorLockout(ISessionCallback*);
void clearLockout(ISessionCallback* cb);
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
index fe405f4..45b5be8 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
@@ -421,29 +421,29 @@
TEST_F(FakeFingerprintEngineTest, parseIntSequence) {
std::vector<int32_t> seqV;
- seqV = mEngine.parseIntSequence("");
+ seqV = Util::parseIntSequence("");
ASSERT_EQ(0, seqV.size());
- seqV = mEngine.parseIntSequence("2");
+ seqV = Util::parseIntSequence("2");
ASSERT_EQ(1, seqV.size());
ASSERT_EQ(2, seqV[0]);
- seqV = mEngine.parseIntSequence("2,3,4");
+ seqV = Util::parseIntSequence("2,3,4");
std::vector<int32_t> expV{2, 3, 4};
ASSERT_EQ(expV, seqV);
- seqV = mEngine.parseIntSequence("2,3,a");
+ seqV = Util::parseIntSequence("2,3,a");
ASSERT_EQ(0, seqV.size());
- seqV = mEngine.parseIntSequence("2, 3, 4");
+ seqV = Util::parseIntSequence("2, 3, 4");
ASSERT_EQ(expV, seqV);
- seqV = mEngine.parseIntSequence("123,456");
+ seqV = Util::parseIntSequence("123,456");
ASSERT_EQ(2, seqV.size());
std::vector<int32_t> expV1{123, 456};
ASSERT_EQ(expV1, seqV);
- seqV = mEngine.parseIntSequence("12f3,456");
+ seqV = Util::parseIntSequence("12f3,456");
ASSERT_EQ(0, seqV.size());
}
TEST_F(FakeFingerprintEngineTest, parseEnrollmentCaptureOk) {
std::vector<std::vector<int32_t>> ecV;
- ecV = mEngine.parseEnrollmentCapture("100,200,300");
+ ecV = Util::parseEnrollmentCapture("100,200,300");
ASSERT_EQ(6, ecV.size());
std::vector<std::vector<int32_t>> expE{{100}, {200}, {300}};
std::vector<int32_t> defC{1};
@@ -451,26 +451,26 @@
ASSERT_EQ(expE[i / 2], ecV[i]);
ASSERT_EQ(defC, ecV[i + 1]);
}
- ecV = mEngine.parseEnrollmentCapture("100");
+ ecV = Util::parseEnrollmentCapture("100");
ASSERT_EQ(2, ecV.size());
ASSERT_EQ(expE[0], ecV[0]);
ASSERT_EQ(defC, ecV[1]);
- ecV = mEngine.parseEnrollmentCapture("100-[5,6,7]");
+ ecV = Util::parseEnrollmentCapture("100-[5,6,7]");
std::vector<int32_t> expC{5, 6, 7};
ASSERT_EQ(2, ecV.size());
for (int i = 0; i < ecV.size(); i += 2) {
ASSERT_EQ(expE[i / 2], ecV[i]);
ASSERT_EQ(expC, ecV[i + 1]);
}
- ecV = mEngine.parseEnrollmentCapture("100-[5,6,7], 200, 300-[9,10]");
+ ecV = Util::parseEnrollmentCapture("100-[5,6,7], 200, 300-[9,10]");
std::vector<std::vector<int32_t>> expC1{{5, 6, 7}, {1}, {9, 10}};
ASSERT_EQ(6, ecV.size());
for (int i = 0; i < ecV.size(); i += 2) {
ASSERT_EQ(expE[i / 2], ecV[i]);
ASSERT_EQ(expC1[i / 2], ecV[i + 1]);
}
- ecV = mEngine.parseEnrollmentCapture("100-[5,6,7], 200-[2,1], 300-[9]");
+ ecV = Util::parseEnrollmentCapture("100-[5,6,7], 200-[2,1], 300-[9]");
std::vector<std::vector<int32_t>> expC2{{5, 6, 7}, {2, 1}, {9}};
ASSERT_EQ(ecV.size(), 6);
for (int i = 0; i < ecV.size(); i += 2) {
@@ -484,7 +484,7 @@
"100,2x0,300", "200-[f]", "a,b"};
std::vector<std::vector<int32_t>> ecV;
for (const auto& s : badStr) {
- ecV = mEngine.parseEnrollmentCapture(s);
+ ecV = Util::parseEnrollmentCapture(s);
ASSERT_EQ(ecV.size(), 0);
}
}
@@ -508,7 +508,7 @@
TEST_F(FakeFingerprintEngineTest, lockoutTimer) {
mEngine.startLockoutTimer(200, mCallback.get());
ASSERT_TRUE(mEngine.getLockoutTimerStarted());
- std::this_thread::sleep_for(std::chrono::milliseconds(210));
+ std::this_thread::sleep_for(std::chrono::milliseconds(230));
ASSERT_FALSE(mEngine.getLockoutTimerStarted());
ASSERT_TRUE(mCallback->mLockoutCleared);
}
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index 5872a86..2b2be55 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -11,7 +11,7 @@
name: "android.hardware.camera.metadata",
vendor_available: true,
srcs: ["android/hardware/camera/metadata/*.aidl"],
- frozen: true,
+ frozen: false,
stability: "vintf",
backend: {
cpp: {
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 71d4e41..0290aef 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -108,6 +108,11 @@
ANDROID_FLASH_COLOR_TEMPERATURE,
ANDROID_FLASH_MAX_ENERGY,
ANDROID_FLASH_STATE,
+ ANDROID_FLASH_STRENGTH_LEVEL,
+ ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
+ ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
+ ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
+ ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
ANDROID_FLASH_INFO_AVAILABLE = android.hardware.camera.metadata.CameraMetadataSectionStart.ANDROID_FLASH_INFO_START /* 327680 */,
ANDROID_FLASH_INFO_CHARGE_DURATION,
ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL,
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 56aa690..dd679f3 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -560,6 +560,36 @@
*/
ANDROID_FLASH_STATE,
/**
+ * android.flash.strengthLevel [dynamic, int32, public]
+ *
+ * <p>Flash strength level to be used when manual flash control is active.</p>
+ */
+ ANDROID_FLASH_STRENGTH_LEVEL,
+ /**
+ * android.flash.singleStrengthMaxLevel [static, int32, public]
+ *
+ * <p>Maximum flash brightness level for manual flash control in SINGLE mode.</p>
+ */
+ ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
+ /**
+ * android.flash.singleStrengthDefaultLevel [static, int32, public]
+ *
+ * <p>Default flash brightness level for manual flash control in SINGLE mode.</p>
+ */
+ ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
+ /**
+ * android.flash.torchStrengthMaxLevel [static, int32, public]
+ *
+ * <p>Maximum flash brightness level for manual flash control in TORCH mode</p>
+ */
+ ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
+ /**
+ * android.flash.torchStrengthDefaultLevel [static, int32, public]
+ *
+ * <p>Default flash brightness level for manual flash control in TORCH mode</p>
+ */
+ ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
+ /**
* android.flash.info.available [static, enum, public]
*
* <p>Whether this camera device has a
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index 04db7f3..2d919cc 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -95,13 +95,14 @@
Return<Status> ExternalCameraProviderImpl_2_4::setCallback(
const sp<ICameraProviderCallback>& callback) {
+ if (callback == nullptr) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
{
Mutex::Autolock _l(mLock);
mCallbacks = callback;
}
- if (mCallbacks == nullptr) {
- return Status::OK;
- }
// Send a callback for all devices to initialize
{
for (const auto& pair : mCameraStatusMap) {
diff --git a/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
index 69318c7..07ed689 100644
--- a/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/LegacyCameraProviderImpl_2_4.cpp
@@ -448,11 +448,11 @@
// Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
Return<Status> LegacyCameraProviderImpl_2_4::setCallback(
const sp<ICameraProviderCallback>& callback) {
+ if (callback == nullptr) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
Mutex::Autolock _l(mCbLock);
mCallbacks = callback;
- if (mCallbacks == nullptr) {
- return Status::OK;
- }
// Add and report all presenting external cameras.
for (auto const& statusPair : mCameraStatusMap) {
int id = std::stoi(statusPair.first);
diff --git a/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
index 62ce074..eba49a5 100644
--- a/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
+++ b/camera/provider/2.7/default/ExternalCameraProviderImpl_2_7.cpp
@@ -91,11 +91,11 @@
Return<Status> ExternalCameraProviderImpl_2_7::setCallback(
const sp<ICameraProviderCallback>& callback) {
+ if (callback == nullptr) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
Mutex::Autolock _l(mLock);
mCallbacks = callback;
- if (mCallbacks == nullptr) {
- return Status::OK;
- }
// Send a callback for all devices to initialize
{
for (const auto& pair : mCameraStatusMap) {
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 2845180..b6b5206 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -242,6 +242,7 @@
verifyCameraCharacteristics(chars);
verifyMonochromeCharacteristics(chars);
verifyRecommendedConfigs(chars);
+ verifyHighSpeedRecordingCharacteristics(name, chars);
verifyLogicalOrUltraHighResCameraMetadata(name, device, chars, cameraDeviceNames);
ASSERT_TRUE(ret.isOk());
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index 5f9d605..6a17453 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -831,6 +831,90 @@
ASSERT_TRUE(hasBokehStillCaptureMode || hasBokehContinuousMode || hasVendorMode);
}
+void CameraAidlTest::verifyHighSpeedRecordingCharacteristics(const std::string& cameraName,
+ const CameraMetadata& chars) {
+ const camera_metadata_t* metadata =
+ reinterpret_cast<const camera_metadata_t*>(chars.metadata.data());
+
+ // Check capabilities
+ bool hasHighSpeedRecordingCapability = false;
+ bool hasUltraHighResolutionCapability = false;
+ camera_metadata_ro_entry entry;
+ int rc =
+ find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+ if ((0 == rc) && (entry.count > 0)) {
+ hasHighSpeedRecordingCapability =
+ std::find(entry.data.u8, entry.data.u8 + entry.count,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO) !=
+ entry.data.u8 + entry.count;
+
+ hasUltraHighResolutionCapability =
+ std::find(entry.data.u8, entry.data.u8 + entry.count,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR) !=
+ entry.data.u8 + entry.count;
+ }
+
+ // Check high speed video configurations
+ camera_metadata_ro_entry highSpeedEntry;
+ rc = find_camera_metadata_ro_entry(
+ metadata, ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS, &highSpeedEntry);
+ bool hasHighSpeedEntry = (0 == rc && highSpeedEntry.count > 0);
+
+ camera_metadata_ro_entry highSpeedMaxResEntry;
+ rc = find_camera_metadata_ro_entry(
+ metadata, ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS_MAXIMUM_RESOLUTION,
+ &highSpeedMaxResEntry);
+ bool hasHighSpeedMaxResEntry = (0 == rc && highSpeedMaxResEntry.count > 0);
+
+ // High speed recording configuration entry must be available based on capabilities
+ bool noHighSpeedRecording =
+ !hasHighSpeedRecordingCapability && !hasHighSpeedEntry && !hasHighSpeedMaxResEntry;
+ if (noHighSpeedRecording) {
+ return;
+ }
+ bool hasHighSpeedRecording = hasHighSpeedRecordingCapability && hasHighSpeedEntry &&
+ ((hasHighSpeedMaxResEntry && hasUltraHighResolutionCapability) ||
+ !hasHighSpeedMaxResEntry);
+ ASSERT_TRUE(hasHighSpeedRecording);
+
+ std::string version, cameraId;
+ ASSERT_TRUE(matchDeviceName(cameraName, mProviderType, &version, &cameraId));
+ bool needBatchSizeCheck = (version != CAMERA_DEVICE_API_VERSION_1);
+
+ // Check each entry item
+ ASSERT_TRUE(highSpeedEntry.count > 0 && highSpeedEntry.count % 5 == 0);
+ for (auto i = 4; i < highSpeedEntry.count; i += 5) {
+ int32_t fps_min = highSpeedEntry.data.i32[i - 2];
+ int32_t fps_max = highSpeedEntry.data.i32[i - 1];
+ int32_t batch_size_max = highSpeedEntry.data.i32[i];
+ int32_t allowedMaxBatchSize = fps_max / 30;
+
+ ASSERT_GE(fps_max, 120);
+ ASSERT_TRUE(fps_min % 30 == 0 && fps_max % 30 == 0);
+ if (needBatchSizeCheck) {
+ ASSERT_LE(batch_size_max, 32);
+ ASSERT_TRUE(allowedMaxBatchSize % batch_size_max == 0);
+ }
+ }
+
+ if (hasHighSpeedMaxResEntry) {
+ ASSERT_TRUE(highSpeedMaxResEntry.count > 0 && highSpeedMaxResEntry.count % 5 == 0);
+ for (auto i = 4; i < highSpeedMaxResEntry.count; i += 5) {
+ int32_t fps_min = highSpeedMaxResEntry.data.i32[i - 2];
+ int32_t fps_max = highSpeedMaxResEntry.data.i32[i - 1];
+ int32_t batch_size_max = highSpeedMaxResEntry.data.i32[i];
+ int32_t allowedMaxBatchSize = fps_max / 30;
+
+ ASSERT_GE(fps_max, 120);
+ ASSERT_TRUE(fps_min % 30 == 0 && fps_max % 30 == 0);
+ if (needBatchSizeCheck) {
+ ASSERT_LE(batch_size_max, 32);
+ ASSERT_TRUE(allowedMaxBatchSize % batch_size_max == 0);
+ }
+ }
+ }
+}
+
Status CameraAidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
std::vector<AvailableStream>& outputStreams,
const AvailableStream* threshold,
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index 6f8f380..3018d5a 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -253,6 +253,9 @@
static void verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata);
+ void verifyHighSpeedRecordingCharacteristics(const std::string& cameraName,
+ const CameraMetadata& chars);
+
static void verifyZoomCharacteristics(const camera_metadata_t* metadata);
static void verifyRecommendedConfigs(const CameraMetadata& chars);
@@ -610,6 +613,8 @@
namespace {
// device@<major>.<minor>/<type>/id
const char* kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/\\s+/(.+)";
+const std::string CAMERA_DEVICE_API_VERSION_1 = "1.1";
+
const int32_t kMaxVideoWidth = 4096;
const int32_t kMaxVideoHeight = 2160;
diff --git a/camera/provider/default/ExternalCameraProvider.cpp b/camera/provider/default/ExternalCameraProvider.cpp
index 4d2c847..54875ab 100644
--- a/camera/provider/default/ExternalCameraProvider.cpp
+++ b/camera/provider/default/ExternalCameraProvider.cpp
@@ -75,15 +75,15 @@
ndk::ScopedAStatus ExternalCameraProvider::setCallback(
const std::shared_ptr<ICameraProviderCallback>& in_callback) {
+ if (in_callback == nullptr) {
+ return fromStatus(Status::ILLEGAL_ARGUMENT);
+ }
+
{
Mutex::Autolock _l(mLock);
mCallback = in_callback;
}
- if (mCallback == nullptr) {
- return fromStatus(Status::OK);
- }
-
for (const auto& pair : mCameraStatusMap) {
mCallback->cameraDeviceStatusChange(pair.first, pair.second);
}
diff --git a/cas/1.0/default/DescramblerImpl.cpp b/cas/1.0/default/DescramblerImpl.cpp
index 6b730eb..6d7c304 100644
--- a/cas/1.0/default/DescramblerImpl.cpp
+++ b/cas/1.0/default/DescramblerImpl.cpp
@@ -79,7 +79,7 @@
return false;
}
- return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
+ return holder->requiresSecureDecoderComponent(mime.c_str());
}
static inline bool validateRangeForSize(
diff --git a/cas/1.1/default/DescramblerImpl.cpp b/cas/1.1/default/DescramblerImpl.cpp
index 9d2ead7..237d56b 100644
--- a/cas/1.1/default/DescramblerImpl.cpp
+++ b/cas/1.1/default/DescramblerImpl.cpp
@@ -75,7 +75,7 @@
return false;
}
- return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
+ return holder->requiresSecureDecoderComponent(mime.c_str());
}
static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) {
diff --git a/cas/1.2/default/DescramblerImpl.cpp b/cas/1.2/default/DescramblerImpl.cpp
index 9d2ead7..237d56b 100644
--- a/cas/1.2/default/DescramblerImpl.cpp
+++ b/cas/1.2/default/DescramblerImpl.cpp
@@ -75,7 +75,7 @@
return false;
}
- return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
+ return holder->requiresSecureDecoderComponent(mime.c_str());
}
static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) {
diff --git a/cas/aidl/default/DescramblerImpl.cpp b/cas/aidl/default/DescramblerImpl.cpp
index d658887..0f4e99b 100644
--- a/cas/aidl/default/DescramblerImpl.cpp
+++ b/cas/aidl/default/DescramblerImpl.cpp
@@ -71,7 +71,7 @@
*_aidl_return = false;
}
- *_aidl_return = holder->requiresSecureDecoderComponent(String8(in_mime.c_str()));
+ *_aidl_return = holder->requiresSecureDecoderComponent(in_mime.c_str());
return ScopedAStatus::ok();
}
diff --git a/common/OWNERS b/common/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/common/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 3b022fc..6c37213 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -43,8 +43,9 @@
min_sdk_version: "29",
},
rust: {
- // FMQ is not supported in the rust backend
- enabled: false,
+ // FMQ is not supported in the rust backend, but we need this AIDL interface for
+ // HardwareBuffer.
+ enabled: true,
},
},
frozen: true,
diff --git a/compatibility_matrices/OWNERS b/compatibility_matrices/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/compatibility_matrices/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml
index 9e3b8f9..2a1f4a5 100644
--- a/compatibility_matrices/compatibility_matrix.8.xml
+++ b/compatibility_matrices/compatibility_matrix.8.xml
@@ -120,6 +120,7 @@
<interface>
<name>IFace</name>
<instance>default</instance>
+ <instance>virtual</instance>
</interface>
</hal>
<hal format="aidl" optional="true" updatable-via-apex="true">
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 57fa2bf..0013923 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -102,6 +102,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.automotive.remoteaccess</name>
+ <version>1-2</version>
<interface>
<name>IRemoteAccess</name>
<instance>default</instance>
diff --git a/contexthub/aidl/default/Android.bp b/contexthub/aidl/default/Android.bp
index 74bac69..03213bc 100644
--- a/contexthub/aidl/default/Android.bp
+++ b/contexthub/aidl/default/Android.bp
@@ -57,3 +57,34 @@
],
srcs: ["main.cpp"],
}
+
+prebuilt_etc {
+ name: "android.hardware.contexthub-service.example.rc",
+ src: "android.hardware.contexthub-service.example.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "contexthub-default.xml",
+ src: "contexthub-default.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
+
+apex {
+ name: "com.android.hardware.contexthub",
+ vendor: true,
+ manifest: "apex_manifest.json",
+ file_contexts: "apex_file_contexts",
+ key: "com.android.hardware.key",
+ certificate: ":com.android.hardware.certificate",
+ updatable: false,
+
+ binaries: [
+ "android.hardware.contexthub-service.example",
+ ],
+ prebuilts: [
+ "android.hardware.contexthub-service.example.rc",
+ "contexthub-default.xml",
+ ],
+}
diff --git a/contexthub/aidl/default/android.hardware.contexthub-service.example.rc b/contexthub/aidl/default/android.hardware.contexthub-service.example.rc
new file mode 100644
index 0000000..7d5d2aa
--- /dev/null
+++ b/contexthub/aidl/default/android.hardware.contexthub-service.example.rc
@@ -0,0 +1,4 @@
+service vendor.contexthub-default /apex/com.android.hardware.contexthub/bin/hw/android.hardware.contexthub-service.example
+ class hal
+ user context_hub
+ group context_hub
diff --git a/contexthub/aidl/default/apex_file_contexts b/contexthub/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..c3c67df
--- /dev/null
+++ b/contexthub/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)? u:object_r:vendor_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.contexthub-service\.example u:object_r:hal_contexthub_default_exec:s0
diff --git a/contexthub/aidl/default/apex_manifest.json b/contexthub/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..aed7081
--- /dev/null
+++ b/contexthub/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.contexthub",
+ "version": 1
+}
\ No newline at end of file
diff --git a/drm/aidl/vts/Android.bp b/drm/aidl/vts/Android.bp
index 190f60d..5139036 100644
--- a/drm/aidl/vts/Android.bp
+++ b/drm/aidl/vts/Android.bp
@@ -59,13 +59,13 @@
data: [":libvtswidevine-arm-prebuilts"],
},
arm64: {
- data: [":libvtswidevine-arm64-prebuilts"],
+ data: [":libvtswidevine-arm64-prebuilts", ":libvtswidevine-arm-prebuilts"],
},
x86: {
data: [":libvtswidevine-x86-prebuilts"],
},
x86_64: {
- data: [":libvtswidevine-x86_64-prebuilts"],
+ data: [":libvtswidevine-x86_64-prebuilts", ":libvtswidevine-x86-prebuilts"],
},
},
test_suites: [
diff --git a/dumpstate/aidl/default/Android.bp b/dumpstate/aidl/default/Android.bp
index 45fdc17..a9da69c 100644
--- a/dumpstate/aidl/default/Android.bp
+++ b/dumpstate/aidl/default/Android.bp
@@ -44,3 +44,41 @@
"-DLOG_TAG=\"android.hardware.dumpstate-service.example\"",
],
}
+
+prebuilt_etc {
+ name: "dumpstate-default.xml",
+ src: "dumpstate-default.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "dumpstate-default.rc",
+ src: ":gen-dumpstate-default.rc-for-apex",
+ installable: false,
+}
+
+genrule {
+ name: "gen-dumpstate-default.rc-for-apex",
+ srcs: ["dumpstate-default.rc"],
+ out: ["dumpstate-default-apex.rc"],
+ cmd: "sed -E 's/\\/vendor\\/bin\\/hw/\\/apex\\/com.android.hardware.dumpstate\\/bin\\/hw/' $(in) > $(out)",
+}
+
+apex {
+ name: "com.android.hardware.dumpstate",
+ vendor: true,
+ manifest: "apex_manifest.json",
+ file_contexts: "apex_file_contexts",
+ key: "com.android.hardware.key",
+ certificate: ":com.android.hardware.certificate",
+ updatable: false,
+
+ binaries: [
+ "android.hardware.dumpstate-service.example",
+ ],
+ prebuilts: [
+ "dumpstate-default.rc",
+ "dumpstate-default.xml",
+ ],
+}
diff --git a/dumpstate/aidl/default/apex_file_contexts b/dumpstate/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..91153a9
--- /dev/null
+++ b/dumpstate/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)? u:object_r:vendor_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.dumpstate-service\.example u:object_r:hal_dumpstate_default_exec:s0
\ No newline at end of file
diff --git a/dumpstate/aidl/default/apex_manifest.json b/dumpstate/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..32beea4
--- /dev/null
+++ b/dumpstate/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.dumpstate",
+ "version": 1
+}
\ No newline at end of file
diff --git a/health/1.0/default/convert.cpp b/health/1.0/default/convert.cpp
index 31b4679..e12e197 100644
--- a/health/1.0/default/convert.cpp
+++ b/health/1.0/default/convert.cpp
@@ -117,7 +117,7 @@
info.batteryCycleCount = p->batteryCycleCount;
info.batteryFullCharge = p->batteryFullCharge;
info.batteryChargeCounter = p->batteryChargeCounter;
- info.batteryTechnology = p->batteryTechnology;
+ info.batteryTechnology = p->batteryTechnology.c_str();
}
void convertFromHealthInfo(const HealthInfo& info,
diff --git a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
index f57a668..1bff076 100644
--- a/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
+++ b/keymaster/4.0/vts/functional/HmacKeySharingTest.cpp
@@ -137,7 +137,7 @@
auto nonces = copyNonces(params);
EXPECT_EQ(allKeymasters().size(), nonces.size());
std::sort(nonces.begin(), nonces.end());
- std::unique(nonces.begin(), nonces.end());
+ nonces.erase(std::unique(nonces.begin(), nonces.end()), nonces.end());
EXPECT_EQ(allKeymasters().size(), nonces.size());
auto responses = computeSharedHmac(allKeymasters(), params);
diff --git a/light/OWNERS b/light/OWNERS
new file mode 100644
index 0000000..d1da8a7
--- /dev/null
+++ b/light/OWNERS
@@ -0,0 +1,5 @@
+# Bug Component: 185877106
+
+michaelwr@google.com
+santoscordon@google.com
+philipjunker@google.com
diff --git a/media/bufferpool/aidl/Android.bp b/media/bufferpool/aidl/Android.bp
index 8caf525..8e013e0 100644
--- a/media/bufferpool/aidl/Android.bp
+++ b/media/bufferpool/aidl/Android.bp
@@ -46,6 +46,9 @@
],
min_sdk_version: "29",
},
+ rust: {
+ enabled: true,
+ },
},
versions_with_info: [
{
diff --git a/media/c2/aidl/Android.bp b/media/c2/aidl/Android.bp
index 75d74ac..3f2cadb 100644
--- a/media/c2/aidl/Android.bp
+++ b/media/c2/aidl/Android.bp
@@ -11,11 +11,12 @@
aidl_interface {
name: "android.hardware.media.c2",
+ min_sdk_version: "31",
vendor_available: true,
double_loadable: true,
srcs: ["android/hardware/media/c2/*.aidl"],
- include_dirs: [
- "frameworks/base/core/java",
+ headers: [
+ "HardwareBuffer_aidl",
],
imports: [
"android.hardware.common-V2",
@@ -31,6 +32,11 @@
},
ndk: {
enabled: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
additional_shared_libraries: [
"libnativewindow",
],
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl
index 460ff97..069b2cf 100644
--- a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/BaseBlock.aidl
@@ -35,5 +35,6 @@
@VintfStability
union BaseBlock {
android.hardware.common.NativeHandle nativeBlock;
+ android.hardware.HardwareBuffer hwbBlock;
android.hardware.media.bufferpool2.BufferStatusMessage pooledBlock;
}
diff --git a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
index da3d5ff..3e460dd 100644
--- a/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
+++ b/media/c2/aidl/aidl_api/android.hardware.media.c2/current/android/hardware/media/c2/IGraphicBufferAllocator.aidl
@@ -36,7 +36,7 @@
interface IGraphicBufferAllocator {
android.hardware.media.c2.IGraphicBufferAllocator.Allocation allocate(in android.hardware.media.c2.IGraphicBufferAllocator.Description desc);
boolean deallocate(in long id);
- android.hardware.media.c2.IGraphicBufferAllocator.WaitableFds getWaitableFds();
+ ParcelFileDescriptor getWaitableFd();
parcelable Allocation {
android.hardware.HardwareBuffer buffer;
ParcelFileDescriptor fence;
@@ -47,8 +47,4 @@
int format;
long usage;
}
- parcelable WaitableFds {
- ParcelFileDescriptor allocEvent;
- ParcelFileDescriptor statusEvent;
- }
}
diff --git a/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl b/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
index 8b8b8e0..7cc041c 100644
--- a/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/BaseBlock.aidl
@@ -16,6 +16,7 @@
package android.hardware.media.c2;
+import android.hardware.HardwareBuffer;
import android.hardware.common.NativeHandle;
/**
@@ -32,6 +33,10 @@
*/
NativeHandle nativeBlock;
/**
+ * #hwbBlock is the opaque representation of a GraphicBuffer
+ */
+ HardwareBuffer hwbBlock;
+ /**
* #pooledBlock is a reference to a buffer handled by a BufferPool.
*/
android.hardware.media.bufferpool2.BufferStatusMessage pooledBlock;
diff --git a/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl b/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
index 1c97214..49c4ea4 100644
--- a/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
+++ b/media/c2/aidl/android/hardware/media/c2/IGraphicBufferAllocator.aidl
@@ -75,31 +75,22 @@
boolean deallocate(in long id);
/**
- * Fds for waitable object events.
- *
- * Fds are created by eventfd() with semaphore mode.
- * For allocEvent, An integer counter regarding dequeuable buffer count is maintained
- * by client using read()/write() to the fd. The fd can be checked whether it is
- * readable via poll(). When in readable status, the specified counter is positive
- * so allocate/dequeue can happen.
- *
- * For statusEvent, the client can notify further allocation is not feasible.
- * e.g.) life-cycle of the underlying allocator is ended.
- *
- * C2Fence object should be implemented based on this Fds. Thus, C2Fence can return
- * either by allocation being ready or allocation being infeasible by the client status
- * change.
- */
- parcelable WaitableFds {
- ParcelFileDescriptor allocEvent;
- ParcelFileDescriptor statusEvent;
- }
-
- /**
- * Gets waiable file descriptors.
+ * Gets a waitable file descriptor.
*
* Use this method once and cache it in order not to create unnecessary duplicated fds.
- * The returned array will have two fds.
+ *
+ * Two file descriptors are created by pipe2(), and the reading end will be returned
+ * and shared by this method. Whenever a dequeuable buffer is ready a byte will be
+ * written to the writing end. Whenever a buffer is allocated(or dequeued) a byte will
+ * be read from the reading end.
+ *
+ * The returned file descriptor(the reading end) can be polled whether the read is ready
+ * via ::poll(). If no more allocate() can be fulfilled(by status change or etc.), the
+ * writing end will be closed. In the case, POLLHUP event can be retrieved via ::poll().
+ *
+ * C2Fence object should be implemented based on this Fd. Thus, C2Fence can return
+ * either by allocation being ready or allocation being infeasible by the client status
+ * change.
*
* If many waitable objects based on the same fd are competing, all watiable objects will be
* notified. After being notified, they should invoke allocate(). At least one of them can
@@ -110,5 +101,5 @@
* @return an fd array which will be wrapped to C2Fence and will be waited for
* until allocating is unblocked.
*/
- WaitableFds getWaitableFds();
+ ParcelFileDescriptor getWaitableFd();
}
diff --git a/memtrack/aidl/default/Android.bp b/memtrack/aidl/default/Android.bp
index 6c77177..cf95bbb 100644
--- a/memtrack/aidl/default/Android.bp
+++ b/memtrack/aidl/default/Android.bp
@@ -37,3 +37,56 @@
"Memtrack.cpp",
],
}
+
+cc_binary {
+ name: "android.hardware.memtrack-service.apex",
+ stem: "android.hardware.memtrack-service.example",
+ relative_install_path: "hw",
+ vendor: true,
+
+ stl: "c++_static",
+ static_libs: [
+ "libbase",
+ "android.hardware.memtrack-V1-ndk",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ ],
+ srcs: [
+ "main.cpp",
+ "Memtrack.cpp",
+ ],
+ installable: false, // installed in APEX
+}
+
+prebuilt_etc {
+ name: "memtrack-default-apex.rc",
+ src: "memtrack-default-apex.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "memtrack-default.xml",
+ src: "memtrack-default.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
+
+apex {
+ name: "com.android.hardware.memtrack",
+ file_contexts: "apex_file_contexts",
+ manifest: "apex_manifest.json",
+ key: "com.android.hardware.key",
+ certificate: ":com.android.hardware.certificate",
+ updatable: false,
+ vendor: true,
+
+ binaries: [
+ "android.hardware.memtrack-service.apex",
+ ],
+ prebuilts: [
+ "memtrack-default-apex.rc",
+ "memtrack-default.xml",
+ ],
+}
diff --git a/memtrack/aidl/default/apex_file_contexts b/memtrack/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..40c0af4
--- /dev/null
+++ b/memtrack/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)? u:object_r:vendor_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.memtrack-service\.example u:object_r:hal_memtrack_default_exec:s0
diff --git a/memtrack/aidl/default/apex_manifest.json b/memtrack/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..16d195e
--- /dev/null
+++ b/memtrack/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.memtrack",
+ "version": 1
+}
\ No newline at end of file
diff --git a/memtrack/aidl/default/memtrack-default-apex.rc b/memtrack/aidl/default/memtrack-default-apex.rc
new file mode 100644
index 0000000..53e712a
--- /dev/null
+++ b/memtrack/aidl/default/memtrack-default-apex.rc
@@ -0,0 +1,4 @@
+service vendor.memtrack-default /apex/com.android.hardware.memtrack/bin/hw/android.hardware.memtrack-service.example
+ class hal
+ user nobody
+ group system
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 253ef82..6643c1e 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -23,6 +23,19 @@
#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+namespace {
+const RadioAccessSpecifierBands EUTRAN_BAND_17 =
+ RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::eutranBands>(
+ {EutranBands::BAND_17});
+const RadioAccessSpecifierBands EUTRAN_BAND_20 =
+ RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::eutranBands>(
+ {EutranBands::BAND_20});
+const RadioAccessSpecifier EUTRAN_SPECIFIER_17 = {
+ .accessNetwork = AccessNetwork::EUTRAN, .bands = EUTRAN_BAND_17, .channels = {1, 2}};
+const RadioAccessSpecifier EUTRAN_SPECIFIER_20 = {
+ .accessNetwork = AccessNetwork::EUTRAN, .bands = EUTRAN_BAND_20, .channels = {128, 129}};
+} // namespace
+
void RadioNetworkTest::SetUp() {
RadioServiceTest::SetUp();
std::string serviceName = GetParam();
@@ -289,7 +302,7 @@
signalThresholdInfo.hysteresisDb = 10; // hysteresisDb too large given threshold list deltas
signalThresholdInfo.thresholds = {-109, -103, -97, -89};
signalThresholdInfo.isEnabled = true;
- signalThresholdInfo.ran = AccessNetwork::GERAN;
+ signalThresholdInfo.ran = AccessNetwork::EUTRAN;
ndk::ScopedAStatus res =
radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo});
@@ -314,7 +327,7 @@
signalThresholdInfo.hysteresisMs = 0;
signalThresholdInfo.hysteresisDb = 0;
signalThresholdInfo.isEnabled = true;
- signalThresholdInfo.ran = AccessNetwork::GERAN;
+ signalThresholdInfo.ran = AccessNetwork::EUTRAN;
ndk::ScopedAStatus res =
radio_network->setSignalStrengthReportingCriteria(serial, {signalThresholdInfo});
@@ -351,7 +364,8 @@
ALOGI("setSignalStrengthReportingCriteria_Geran, rspInfo.error = %s\n",
toString(radioRsp_network->rspInfo.error).c_str());
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
}
/*
@@ -677,7 +691,7 @@
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
if (radioRsp_network->rspInfo.error == RadioError::NONE) {
- supportedSignalThresholdInfos.push_back(signalThresholdInfoGeran);
+ supportedSignalThresholdInfos.push_back(signalThresholdInfoEutran);
} else {
// Refer to IRadioNetworkResponse#setSignalStrengthReportingCriteriaResponse
ASSERT_TRUE(CheckAnyOfErrors(
@@ -711,7 +725,7 @@
ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria(
serial, 5000,
5000, // hysteresisDlKbps too big for thresholds delta
- 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::GERAN);
+ 100, {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::EUTRAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -719,11 +733,7 @@
ALOGI("setLinkCapacityReportingCriteria_invalidHysteresisDlKbps, rspInfo.error = %s\n",
toString(radioRsp_network->rspInfo.error).c_str());
- // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported
- // for GERAN
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_network->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
/*
@@ -734,7 +744,7 @@
ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria(
serial, 5000, 500, 1000, // hysteresisUlKbps too big for thresholds delta
- {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::GERAN);
+ {1000, 5000, 10000, 20000}, {500, 1000, 5000, 10000}, AccessNetwork::EUTRAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -742,11 +752,7 @@
ALOGI("setLinkCapacityReportingCriteria_invalidHysteresisUlKbps, rspInfo.error = %s\n",
toString(radioRsp_network->rspInfo.error).c_str());
- // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported
- // for GERAN
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_network->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
/*
@@ -756,7 +762,7 @@
serial = GetRandomSerialNumber();
ndk::ScopedAStatus res = radio_network->setLinkCapacityReportingCriteria(
- serial, 0, 0, 0, {}, {}, AccessNetwork::GERAN);
+ serial, 0, 0, 0, {}, {}, AccessNetwork::EUTRAN);
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -764,10 +770,7 @@
ALOGI("setLinkCapacityReportingCriteria_emptyParams, rspInfo.error = %s\n",
toString(radioRsp_network->rspInfo.error).c_str());
- // Allow REQUEST_NOT_SUPPORTED as setLinkCapacityReportingCriteria() may not be supported
- // for GERAN
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE}));
}
/*
@@ -808,19 +811,9 @@
}
std::vector<RadioAccessSpecifier> originalSpecifiers = radioRsp_network->specifiers;
- RadioAccessSpecifierBands bandP900 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_P900});
- RadioAccessSpecifierBands band850 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_850});
- RadioAccessSpecifier specifierP900 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
- RadioAccessSpecifier specifier850 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
serial = GetRandomSerialNumber();
- res = radio_network->setSystemSelectionChannels(serial, true, {specifierP900, specifier850});
+ res = radio_network->setSystemSelectionChannels(serial, true,
+ {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20});
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -833,8 +826,8 @@
if (radioRsp_network->rspInfo.error == RadioError::NONE) {
serial = GetRandomSerialNumber();
- res = radio_network->setSystemSelectionChannels(serial, false,
- {specifierP900, specifier850});
+ res = radio_network->setSystemSelectionChannels(
+ serial, false, {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20});
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
@@ -857,20 +850,9 @@
TEST_P(RadioNetworkTest, startNetworkScan) {
serial = GetRandomSerialNumber();
- RadioAccessSpecifierBands band17 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::eutranBands>(
- {EutranBands::BAND_17});
- RadioAccessSpecifierBands band20 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::eutranBands>(
- {EutranBands::BAND_20});
- RadioAccessSpecifier specifier17 = {
- .accessNetwork = AccessNetwork::EUTRAN, .bands = band17, .channels = {1, 2}};
- RadioAccessSpecifier specifier20 = {
- .accessNetwork = AccessNetwork::EUTRAN, .bands = band20, .channels = {128, 129}};
-
NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
.interval = 60,
- .specifiers = {specifier17, specifier20},
+ .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
.maxSearchTime = 60,
.incrementalResults = false,
.incrementalResultsPeriodicity = 1};
@@ -892,10 +874,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
{RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED}));
} else {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED, RadioError::NONE,
- RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED,
+ RadioError::INVALID_ARGUMENTS}));
}
}
@@ -925,9 +906,8 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -937,20 +917,9 @@
TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval1) {
serial = GetRandomSerialNumber();
- RadioAccessSpecifierBands bandP900 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_P900});
- RadioAccessSpecifierBands band850 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_850});
- RadioAccessSpecifier specifierP900 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
- RadioAccessSpecifier specifier850 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC,
.interval = 4,
- .specifiers = {specifierP900, specifier850},
+ .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
.maxSearchTime = 60,
.incrementalResults = false,
.incrementalResultsPeriodicity = 1};
@@ -966,9 +935,8 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -978,20 +946,9 @@
TEST_P(RadioNetworkTest, startNetworkScan_InvalidInterval2) {
serial = GetRandomSerialNumber();
- RadioAccessSpecifierBands bandP900 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_P900});
- RadioAccessSpecifierBands band850 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_850});
- RadioAccessSpecifier specifierP900 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
- RadioAccessSpecifier specifier850 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_PERIODIC,
.interval = 301,
- .specifiers = {specifierP900, specifier850},
+ .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
.maxSearchTime = 60,
.incrementalResults = false,
.incrementalResultsPeriodicity = 1};
@@ -1007,9 +964,8 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -1019,20 +975,9 @@
TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime1) {
serial = GetRandomSerialNumber();
- RadioAccessSpecifierBands bandP900 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_P900});
- RadioAccessSpecifierBands band850 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_850});
- RadioAccessSpecifier specifierP900 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
- RadioAccessSpecifier specifier850 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
.interval = 60,
- .specifiers = {specifierP900, specifier850},
+ .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
.maxSearchTime = 59,
.incrementalResults = false,
.incrementalResultsPeriodicity = 1};
@@ -1048,9 +993,8 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -1060,20 +1004,9 @@
TEST_P(RadioNetworkTest, startNetworkScan_InvalidMaxSearchTime2) {
serial = GetRandomSerialNumber();
- RadioAccessSpecifierBands bandP900 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_P900});
- RadioAccessSpecifierBands band850 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_850});
- RadioAccessSpecifier specifierP900 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
- RadioAccessSpecifier specifier850 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
.interval = 60,
- .specifiers = {specifierP900, specifier850},
+ .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
.maxSearchTime = 3601,
.incrementalResults = false,
.incrementalResultsPeriodicity = 1};
@@ -1089,9 +1022,8 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -1101,20 +1033,9 @@
TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity1) {
serial = GetRandomSerialNumber();
- RadioAccessSpecifierBands bandP900 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_P900});
- RadioAccessSpecifierBands band850 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_850});
- RadioAccessSpecifier specifierP900 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
- RadioAccessSpecifier specifier850 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
.interval = 60,
- .specifiers = {specifierP900, specifier850},
+ .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
.maxSearchTime = 600,
.incrementalResults = true,
.incrementalResultsPeriodicity = 0};
@@ -1130,9 +1051,8 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -1142,20 +1062,9 @@
TEST_P(RadioNetworkTest, startNetworkScan_InvalidPeriodicity2) {
serial = GetRandomSerialNumber();
- RadioAccessSpecifierBands bandP900 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_P900});
- RadioAccessSpecifierBands band850 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_850});
- RadioAccessSpecifier specifierP900 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
- RadioAccessSpecifier specifier850 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
.interval = 60,
- .specifiers = {specifierP900, specifier850},
+ .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
.maxSearchTime = 600,
.incrementalResults = true,
.incrementalResultsPeriodicity = 11};
@@ -1171,9 +1080,8 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
}
}
@@ -1183,20 +1091,9 @@
TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest1) {
serial = GetRandomSerialNumber();
- RadioAccessSpecifierBands bandP900 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_P900});
- RadioAccessSpecifierBands band850 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_850});
- RadioAccessSpecifier specifierP900 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
- RadioAccessSpecifier specifier850 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
.interval = 60,
- .specifiers = {specifierP900, specifier850},
+ .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
.maxSearchTime = 360,
.incrementalResults = false,
.incrementalResultsPeriodicity = 10};
@@ -1213,8 +1110,7 @@
{RadioError::NONE, RadioError::SIM_ABSENT}));
} else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
- RadioError::REQUEST_NOT_SUPPORTED}));
+ {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
}
if (radioRsp_network->rspInfo.error == RadioError::NONE) {
@@ -1229,20 +1125,9 @@
TEST_P(RadioNetworkTest, startNetworkScan_GoodRequest2) {
serial = GetRandomSerialNumber();
- RadioAccessSpecifierBands bandP900 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_P900});
- RadioAccessSpecifierBands band850 =
- RadioAccessSpecifierBands::make<RadioAccessSpecifierBands::geranBands>(
- {GeranBands::BAND_850});
- RadioAccessSpecifier specifierP900 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = bandP900, .channels = {1, 2}};
- RadioAccessSpecifier specifier850 = {
- .accessNetwork = AccessNetwork::GERAN, .bands = band850, .channels = {128, 129}};
-
NetworkScanRequest request = {.type = NetworkScanRequest::SCAN_TYPE_ONE_SHOT,
.interval = 60,
- .specifiers = {specifierP900, specifier850},
+ .specifiers = {::EUTRAN_SPECIFIER_17, ::EUTRAN_SPECIFIER_20},
.maxSearchTime = 360,
.incrementalResults = false,
.incrementalResultsPeriodicity = 10,
@@ -1260,8 +1145,7 @@
{RadioError::NONE, RadioError::SIM_ABSENT}));
} else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
- RadioError::REQUEST_NOT_SUPPORTED}));
+ {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
}
if (radioRsp_network->rspInfo.error == RadioError::NONE) {
@@ -1278,21 +1162,23 @@
// can't camp on nonexistent MCCMNC, so we expect this to fail.
ndk::ScopedAStatus res =
- radio_network->setNetworkSelectionModeManual(serial, "123456", AccessNetwork::GERAN);
+ radio_network->setNetworkSelectionModeManual(serial, "123456", AccessNetwork::EUTRAN);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME,
- RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE},
- CHECK_GENERAL_ERROR));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME, RadioError::INVALID_ARGUMENTS,
+ RadioError::INVALID_STATE, RadioError::RADIO_NOT_AVAILABLE, RadioError::NO_MEMORY,
+ RadioError::INTERNAL_ERR, RadioError::SYSTEM_ERR, RadioError::CANCELLED}));
} else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
- RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE},
- CHECK_GENERAL_ERROR));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::INVALID_ARGUMENTS,
+ RadioError::INVALID_STATE, RadioError::NO_MEMORY, RadioError::INTERNAL_ERR,
+ RadioError::SYSTEM_ERR, RadioError::CANCELLED}));
}
}
diff --git a/rebootescrow/OWNERS b/rebootescrow/OWNERS
new file mode 100644
index 0000000..c9701ff
--- /dev/null
+++ b/rebootescrow/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 63928581
+
+kroot@google.com
+paulcrowley@google.com
diff --git a/rebootescrow/aidl/default/OWNERS b/rebootescrow/aidl/default/OWNERS
deleted file mode 100644
index c5288d6..0000000
--- a/rebootescrow/aidl/default/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-kroot@google.com
-paulcrowley@google.com
diff --git a/rebootescrow/aidl/vts/OWNERS b/rebootescrow/aidl/vts/OWNERS
deleted file mode 100644
index c5288d6..0000000
--- a/rebootescrow/aidl/vts/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-kroot@google.com
-paulcrowley@google.com
diff --git a/scripts/OWNERS b/scripts/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/scripts/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp b/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp
index 97b4e27..9678da4 100644
--- a/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp
+++ b/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp
@@ -293,11 +293,13 @@
std::vector<uint8_t> response;
LogicalChannelResponse logical_channel_response;
+ /* Temporaly disable this check to clarify Basic Channel behavior (b/300502872)
// Note: no channel is opened for this test
// transmit() will return an empty response with the error
// code CHANNEL_NOT_AVAILABLE when the SE cannot be
// communicated with.
EXPECT_ERR(secure_element_->transmit(kDataApdu, &response));
+ */
EXPECT_OK(secure_element_->openLogicalChannel(kSelectableAid, 0x00, &logical_channel_response));
EXPECT_GE(logical_channel_response.selectResponse.size(), 2u);
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 2e4fc15..aeb0163 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -379,6 +379,12 @@
* validate it against the key material. In the event of a mismatch, importKey must return
* ErrorCode::IMPORT_PARAMETER_MISMATCH.
*
+ * o Tag::EC_CURVE is not necessary in the input parameters for import of EC keys. If not
+ * provided the IKeyMintDevice must deduce the value from the provided key material and add
+ * the tag and value to the key characteristics. If Tag::EC_CURVE is provided, the
+ * IKeyMintDevice must validate it against the key material. In the event of a mismatch,
+ * importKey must return ErrorCode::IMPORT_PARAMETER_MISMATCH.
+ *
* o Tag::RSA_PUBLIC_EXPONENT (for RSA keys only) is not necessary in the input parameters. If
* not provided, the IKeyMintDevice must deduce the value from the provided key material and
* add the tag and value to the key characteristics. If Tag::RSA_PUBLIC_EXPONENT is provided,
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 4c46719..cc97c13 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -88,30 +88,6 @@
return imei;
}
-
-// Use `ro.product.<property>_for_attestation` property for attestation if it is present else
-// fallback to use `ro.product.vendor.<property>` if it is present else fallback to
-// `ro.product.<property>`. Similar logic can be seen in Java method `getVendorDeviceIdProperty`
-// in frameworks/base/core/java/android/os/Build.java.
-template <Tag tag>
-void add_attestation_id(AuthorizationSetBuilder* attestation_id_tags,
- TypedTag<TagType::BYTES, tag> tag_type, const char* prop) {
- ::android::String8 prop_name =
- ::android::String8::format("ro.product.%s_for_attestation", prop);
- std::string prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
- } else {
- prop_name = ::android::String8::format("ro.product.vendor.%s", prop);
- prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
- } else {
- prop_name = ::android::String8::format("ro.product.%s", prop);
- add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
- }
- }
-}
} // namespace
class AttestKeyTest : public KeyMintAidlTestBase {
diff --git a/security/keymint/aidl/vts/functional/AuthTest.cpp b/security/keymint/aidl/vts/functional/AuthTest.cpp
index d5c6d2a..eb5db68 100644
--- a/security/keymint/aidl/vts/functional/AuthTest.cpp
+++ b/security/keymint/aidl/vts/functional/AuthTest.cpp
@@ -350,14 +350,14 @@
// Wait for long enough that the hardware auth token expires.
sleep(timeout_secs + 1);
- if (!timestamp_token_required_) {
- // KeyMint implementation has its own clock, and can immediately detect timeout.
- EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
- Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat));
- } else {
- // KeyMint implementation has no clock, so only detects timeout via timestamp token provided
- // on update()/finish().
- ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat));
+
+ auto begin_result = Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat);
+ if (begin_result == ErrorCode::OK) {
+ // If begin() succeeds despite the out-of-date HAT, that must mean that the KeyMint
+ // device doesn't have its own clock. In that case, it only detects timeout via a
+ // timestamp token provided on update()/finish()
+ ASSERT_TRUE(timestamp_token_required_);
+
secureclock::TimeStampToken time_token;
EXPECT_EQ(ErrorCode::OK,
GetReturnErrorCode(clock_->generateTimeStamp(challenge_, &time_token)));
@@ -365,6 +365,9 @@
string output;
EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
Finish(message, {} /* signature */, &output, hat, time_token));
+ } else {
+ // The KeyMint implementation may have its own clock that can immediately detect timeout.
+ ASSERT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED, begin_result);
}
}
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 5f8ec0e..3a8a1e8 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -841,7 +841,7 @@
int vendor_api_level = property_get_int32("ro.vendor.api_level", 0);
if (SecLevel() == SecurityLevel::STRONGBOX) {
// This is known to be broken on older vendor implementations.
- if (vendor_api_level < __ANDROID_API_T__) {
+ if (vendor_api_level <= __ANDROID_API_U__) {
compare_output = false;
} else {
additional_information = " (b/194134359) ";
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 8934a57..9778b3d 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -454,6 +454,29 @@
::android::PrintInstanceNameToString); \
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name);
+// Use `ro.product.<property>_for_attestation` property for attestation if it is present else
+// fallback to use `ro.product.vendor.<property>` if it is present else fallback to
+// `ro.product.<property>`. Similar logic can be seen in Java method `getVendorDeviceIdProperty`
+// in frameworks/base/core/java/android/os/Build.java.
+template <Tag tag>
+void add_attestation_id(AuthorizationSetBuilder* attestation_id_tags,
+ TypedTag<TagType::BYTES, tag> tag_type, const char* prop) {
+ ::android::String8 prop_name =
+ ::android::String8::format("ro.product.%s_for_attestation", prop);
+ std::string prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
+ if (!prop_value.empty()) {
+ add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
+ } else {
+ prop_name = ::android::String8::format("ro.product.vendor.%s", prop);
+ prop_value = ::android::base::GetProperty(prop_name.c_str(), /* default= */ "");
+ if (!prop_value.empty()) {
+ add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
+ } else {
+ prop_name = ::android::String8::format("ro.product.%s", prop);
+ add_tag_from_prop(attestation_id_tags, tag_type, prop_name.c_str());
+ }
+ }
+}
} // namespace test
} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 022dd3f..de563c4 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -2082,11 +2082,6 @@
* attestation extension.
*/
TEST_P(NewKeyGenerationTest, EcdsaAttestationIdTags) {
- if (is_gsi_image()) {
- // GSI sets up a standard set of device identifiers that may not match
- // the device identifiers held by the device.
- GTEST_SKIP() << "Test not applicable under GSI";
- }
auto challenge = "hello";
auto app_id = "foo";
auto subject = "cert subj 2";
@@ -2106,38 +2101,12 @@
// Various ATTESTATION_ID_* tags that map to fields in the attestation extension ASN.1 schema.
auto extra_tags = AuthorizationSetBuilder();
- // Use ro.product.brand_for_attestation property for attestation if it is present else fallback
- // to ro.product.brand
- std::string prop_value =
- ::android::base::GetProperty("ro.product.brand_for_attestation", /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_BRAND,
- "ro.product.brand_for_attestation");
- } else {
- add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
- }
- add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
- // Use ro.product.name_for_attestation property for attestation if it is present else fallback
- // to ro.product.name
- prop_value = ::android::base::GetProperty("ro.product.name_for_attestation", /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_PRODUCT,
- "ro.product.name_for_attestation");
- } else {
- add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
- }
+ add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_BRAND, "brand");
+ add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "device");
+ add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "name");
+ add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer");
+ add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MODEL, "model");
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
- add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "ro.product.manufacturer");
- // Use ro.product.model_for_attestation property for attestation if it is present else fallback
- // to ro.product.model
- prop_value =
- ::android::base::GetProperty("ro.product.model_for_attestation", /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MODEL,
- "ro.product.model_for_attestation");
- } else {
- add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
- }
for (const KeyParameter& tag : extra_tags) {
SCOPED_TRACE(testing::Message() << "tag-" << tag);
@@ -2611,16 +2580,16 @@
/*
* NewKeyGenerationTest.EcdsaMissingCurve
*
- * Verifies that EC key generation fails if EC_CURVE not specified after KeyMint V2.
+ * Verifies that EC key generation fails if EC_CURVE not specified after KeyMint V3.
*/
TEST_P(NewKeyGenerationTest, EcdsaMissingCurve) {
- if (AidlVersion() < 2) {
+ if (AidlVersion() < 3) {
/*
* The KeyMint V1 spec required that EC_CURVE be specified for EC keys.
* However, this was not checked at the time so we can only be strict about checking this
- * for implementations of KeyMint version 2 and above.
+ * for implementations of KeyMint version 3 and above.
*/
- GTEST_SKIP() << "Requiring EC_CURVE only strict since KeyMint v2";
+ GTEST_SKIP() << "Requiring EC_CURVE only strict since KeyMint v3";
}
/* If EC_CURVE not provided, generateKey
* must return ErrorCode::UNSUPPORTED_KEY_SIZE or ErrorCode::UNSUPPORTED_EC_CURVE.
@@ -4148,6 +4117,42 @@
}
/*
+ * ImportKeyTest.EcdsaSuccessCurveNotSpecified
+ *
+ * Verifies that importing and using an ECDSA P-256 key pair works correctly
+ * when the EC_CURVE is not explicitly specified.
+ */
+TEST_P(ImportKeyTest, EcdsaSuccessCurveNotSpecified) {
+ if (AidlVersion() < 4) {
+ /*
+ * The KeyMint spec before V4 was not clear as to whether EC_CURVE was optional on import of
+ * EC keys. However, this was not checked at the time so we can only be strict about
+ * checking this for implementations of KeyMint version 4 and above.
+ */
+ GTEST_SKIP() << "Skipping EC_CURVE on import only strict since KeyMint v4";
+ }
+
+ ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ALGORITHM, Algorithm::EC)
+ .SigningKey()
+ .Digest(Digest::SHA_2_256)
+ .SetDefaultValidity(),
+ KeyFormat::PKCS8, ec_256_key));
+
+ CheckCryptoParam(TAG_ALGORITHM, Algorithm::EC);
+ CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
+ CheckCryptoParam(TAG_EC_CURVE, EcCurve::P_256);
+
+ CheckOrigin();
+
+ string message(32, 'a');
+ auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
+ string signature = SignMessage(message, params);
+ LocalVerifyMessage(message, signature, params);
+}
+
+/*
* ImportKeyTest.EcdsaP256RFC5915Success
*
* Verifies that importing and using an ECDSA P-256 key pair encoded using RFC5915 works
@@ -4792,7 +4797,7 @@
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
string result;
- EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+ EXPECT_NE(ErrorCode::OK, Finish(ciphertext1, &result));
EXPECT_EQ(0U, result.size());
}
}
@@ -5300,7 +5305,7 @@
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
string result;
- EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+ EXPECT_NE(ErrorCode::OK, Finish(ciphertext1, &result));
EXPECT_EQ(0U, result.size());
}
}
@@ -5367,7 +5372,7 @@
.Digest(Digest::SHA_2_256)
.Padding(PaddingMode::RSA_OAEP)));
string result;
- EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result));
+ EXPECT_NE(ErrorCode::OK, Finish(ciphertext, &result));
EXPECT_EQ(0U, result.size());
}
@@ -5437,7 +5442,7 @@
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
string result;
- EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+ EXPECT_NE(ErrorCode::OK, Finish(ciphertext1, &result));
EXPECT_EQ(0U, result.size());
}
}
@@ -5481,7 +5486,7 @@
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
string result;
- EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext, &result));
+ EXPECT_NE(ErrorCode::OK, Finish(ciphertext, &result));
EXPECT_EQ(0U, result.size());
}
@@ -5613,7 +5618,7 @@
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
string result;
- EXPECT_EQ(ErrorCode::UNKNOWN_ERROR, Finish(ciphertext1, &result));
+ EXPECT_NE(ErrorCode::OK, Finish(ciphertext1, &result));
EXPECT_EQ(0U, result.size());
}
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 780c3d2..34f7ce4 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -962,6 +962,20 @@
return signedRequest->value();
}
+ErrMsgOr<hwtrust::DiceChain::Kind> getDiceChainKind() {
+ int vendor_api_level = ::android::base::GetIntProperty("ro.vendor.api_level", -1);
+ switch (vendor_api_level) {
+ case __ANDROID_API_T__:
+ return hwtrust::DiceChain::Kind::kVsr13;
+ case __ANDROID_API_U__:
+ return hwtrust::DiceChain::Kind::kVsr14;
+ case __ANDROID_API_V__:
+ return hwtrust::DiceChain::Kind::kVsr15;
+ default:
+ return "Unsupported vendor API level: " + std::to_string(vendor_api_level);
+ }
+}
+
ErrMsgOr<bytevec> parseAndValidateAuthenticatedRequest(const std::vector<uint8_t>& request,
const std::vector<uint8_t>& challenge) {
auto [parsedRequest, _, csrErrMsg] = cppbor::parse(request);
@@ -996,7 +1010,12 @@
}
// DICE chain is [ pubkey, + DiceChainEntry ].
- auto diceContents = validateBcc(diceCertChain, hwtrust::DiceChain::Kind::kVsr14);
+ auto diceChainKind = getDiceChainKind();
+ if (!diceChainKind) {
+ return diceChainKind.message();
+ }
+
+ auto diceContents = validateBcc(diceCertChain, *diceChainKind);
if (!diceContents) {
return diceContents.message() + "\n" + prettyPrint(diceCertChain);
}
diff --git a/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
index 80f7cbd..15b0442 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
+++ b/security/rkp/aidl/android/hardware/security/keymint/generateCertificateRequestV2.cddl
@@ -90,9 +90,10 @@
DiceChainEntryPayload = { ; CWT [RFC8392]
1 : tstr, ; Issuer
2 : tstr, ; Subject
+ -4670554 : "android.15", ; Profile Name
-4670552 : bstr .cbor PubKeyEd25519 /
bstr .cbor PubKeyECDSA256 /
- bstr .cbor PubKeyECDSA384, ; Subject Public Key
+ bstr .cbor PubKeyECDSA384, ; Subject Public Key
-4670553 : bstr ; Key Usage
; NOTE: All of the following fields may be omitted for a "Degenerate DICE Chain", as
diff --git a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
index 51938ba..7599bce 100644
--- a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
+++ b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
@@ -164,7 +164,7 @@
auto nonces = copyNonces(params);
EXPECT_EQ(sharedSecrets.size(), nonces.size());
std::sort(nonces.begin(), nonces.end());
- std::unique(nonces.begin(), nonces.end());
+ nonces.erase(std::unique(nonces.begin(), nonces.end()), nonces.end());
EXPECT_EQ(sharedSecrets.size(), nonces.size());
auto responses = computeAllSharedSecrets(params);
diff --git a/soundtrigger/aidl/cli/java/android/hardware/soundtrigger3/cli/SthalCli.java b/soundtrigger/aidl/cli/java/android/hardware/soundtrigger3/cli/SthalCli.java
index 127f062..41e2533 100644
--- a/soundtrigger/aidl/cli/java/android/hardware/soundtrigger3/cli/SthalCli.java
+++ b/soundtrigger/aidl/cli/java/android/hardware/soundtrigger3/cli/SthalCli.java
@@ -289,6 +289,8 @@
Properties properties = new Properties();
properties.implementor = "Android";
properties.description = "Mock STHAL";
+ properties.uuid = "a5af2d2a-4cc4-4b69-a22f-c9d5b6d492c3";
+ properties.supportedModelArch = "Mock arch";
properties.maxSoundModels = 2;
properties.maxKeyPhrases = 1;
properties.recognitionModes =
diff --git a/staging/OWNERS b/staging/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/staging/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/tests/OWNERS b/tests/OWNERS
new file mode 100644
index 0000000..a07824e
--- /dev/null
+++ b/tests/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 298954331
+
+include platform/hardware/interfaces:/OWNERS
diff --git a/tetheroffload/aidl/default/Android.bp b/tetheroffload/aidl/default/Android.bp
index 8f0739c..8c96990 100644
--- a/tetheroffload/aidl/default/Android.bp
+++ b/tetheroffload/aidl/default/Android.bp
@@ -19,18 +19,52 @@
cc_binary {
name: "android.hardware.tetheroffload-service.example",
relative_install_path: "hw",
- init_rc: ["tetheroffload-example.rc"],
- vintf_fragments: ["tetheroffload-example.xml"],
vendor: true,
- shared_libs: [
+
+ stl: "c++_static",
+ static_libs: [
"android.hardware.tetheroffload-V1-ndk",
"libbase",
+ ],
+ shared_libs: [
"libbinder_ndk",
- "libcutils",
- "libutils",
+ "liblog",
],
srcs: [
"main.cpp",
"Offload.cpp",
],
+
+ installable: false, // installed in APEX
+}
+
+prebuilt_etc {
+ name: "tetheroffload-example.rc",
+ src: "tetheroffload-example.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "tetheroffload-example.xml",
+ src: "tetheroffload-example.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
+
+apex {
+ name: "com.android.hardware.tetheroffload",
+ manifest: "apex_manifest.json",
+ file_contexts: "apex_file_contexts",
+ key: "com.android.hardware.key",
+ certificate: ":com.android.hardware.certificate",
+ updatable: false,
+ vendor: true,
+
+ binaries: [
+ "android.hardware.tetheroffload-service.example",
+ ],
+ prebuilts: [
+ "tetheroffload-example.rc",
+ "tetheroffload-example.xml",
+ ],
}
diff --git a/tetheroffload/aidl/default/apex_file_contexts b/tetheroffload/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..a520101
--- /dev/null
+++ b/tetheroffload/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)? u:object_r:vendor_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.tetheroffload-service\.example u:object_r:hal_tetheroffload_default_exec:s0
diff --git a/tetheroffload/aidl/default/apex_manifest.json b/tetheroffload/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..4c90889
--- /dev/null
+++ b/tetheroffload/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.tetheroffload",
+ "version": 1
+}
diff --git a/tetheroffload/aidl/default/tetheroffload-example.rc b/tetheroffload/aidl/default/tetheroffload-example.rc
index 46cda61..b95544b 100644
--- a/tetheroffload/aidl/default/tetheroffload-example.rc
+++ b/tetheroffload/aidl/default/tetheroffload-example.rc
@@ -1,4 +1,4 @@
-service vendor.tetheroffload-example /vendor/bin/hw/android.hardware.tetheroffload-service.example
+service vendor.tetheroffload-example /apex/com.android.hardware.tetheroffload/bin/hw/android.hardware.tetheroffload-service.example
class hal
user nobody
group nobody
diff --git a/thermal/aidl/default/Android.bp b/thermal/aidl/default/Android.bp
index 49a578b..451e1e2 100644
--- a/thermal/aidl/default/Android.bp
+++ b/thermal/aidl/default/Android.bp
@@ -24,26 +24,50 @@
cc_binary {
name: "android.hardware.thermal-service.example",
relative_install_path: "hw",
- init_rc: [":android.hardware.thermal.example.rc"],
- vintf_fragments: [":android.hardware.thermal.example.xml"],
vendor: true,
- shared_libs: [
- "libbase",
- "libbinder_ndk",
+ stl: "c++_static",
+ static_libs: [
"android.hardware.thermal-V1-ndk",
+ "libbase",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
],
srcs: [
"main.cpp",
"Thermal.cpp",
],
+ installable: false,
}
-filegroup {
+prebuilt_etc {
name: "android.hardware.thermal.example.xml",
- srcs: ["thermal-example.xml"],
+ src: "thermal-example.xml",
+ sub_dir: "vintf",
+ installable: false,
}
-filegroup {
+prebuilt_etc {
name: "android.hardware.thermal.example.rc",
- srcs: ["thermal-example.rc"],
+ src: "thermal-example.rc",
+ installable: false,
+}
+
+apex {
+ name: "com.android.hardware.thermal",
+ manifest: "apex_manifest.json",
+ file_contexts: "apex_file_contexts",
+ key: "com.android.hardware.key",
+ certificate: ":com.android.hardware.certificate",
+ updatable: false,
+ vendor: true,
+
+ binaries: [
+ "android.hardware.thermal-service.example",
+ ],
+ prebuilts: [
+ "android.hardware.thermal.example.xml",
+ "android.hardware.thermal.example.rc",
+ ],
}
diff --git a/thermal/aidl/default/apex_file_contexts b/thermal/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..9fa5339
--- /dev/null
+++ b/thermal/aidl/default/apex_file_contexts
@@ -0,0 +1,3 @@
+(/.*)? u:object_r:vendor_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.thermal-service\.example u:object_r:hal_thermal_default_exec:s0
diff --git a/thermal/aidl/default/apex_manifest.json b/thermal/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..80420d5
--- /dev/null
+++ b/thermal/aidl/default/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.hardware.thermal",
+ "version": 1
+}
diff --git a/thermal/aidl/default/thermal-example.rc b/thermal/aidl/default/thermal-example.rc
index 591ca03..36dde0d 100644
--- a/thermal/aidl/default/thermal-example.rc
+++ b/thermal/aidl/default/thermal-example.rc
@@ -1,4 +1,4 @@
-service vendor.thermal-example /vendor/bin/hw/android.hardware.thermal-service.example
+service vendor.thermal-example /apex/com.android.hardware.thermal/bin/hw/android.hardware.thermal-service.example
class hal
user nobody
group system
diff --git a/threadnetwork/aidl/default/Android.bp b/threadnetwork/aidl/default/Android.bp
index 62c8c9e..816f892 100644
--- a/threadnetwork/aidl/default/Android.bp
+++ b/threadnetwork/aidl/default/Android.bp
@@ -83,8 +83,8 @@
}
prebuilt_etc {
- name: "threadnetwork-service-sim.rc",
- src: "threadnetwork-service-sim.rc",
+ name: "threadnetwork-service.rc",
+ src: "threadnetwork-service.rc",
installable: false,
}
@@ -101,9 +101,10 @@
"android.hardware.threadnetwork-service",
"ot-rcp",
],
+
prebuilts: [
"threadnetwork-default.xml", // vintf_fragment
- "threadnetwork-service-sim.rc", // init_rc
+ "threadnetwork-service.rc", // init_rc
"android.hardware.thread_network.prebuilt.xml", // permission
],
}
diff --git a/threadnetwork/aidl/default/threadnetwork-service-sim.rc b/threadnetwork/aidl/default/threadnetwork-service.rc
similarity index 100%
rename from threadnetwork/aidl/default/threadnetwork-service-sim.rc
rename to threadnetwork/aidl/default/threadnetwork-service.rc
diff --git a/weaver/aidl/android/hardware/weaver/IWeaver.aidl b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
index ae816ef..30168e3 100644
--- a/weaver/aidl/android/hardware/weaver/IWeaver.aidl
+++ b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
@@ -58,7 +58,9 @@
* Throttling must be used to limit the frequency of failed read attempts.
* The value is only returned when throttling is not active, even if the
* correct key is provided. If called when throttling is active, the time
- * until the next attempt can be made is returned.
+ * until the next attempt can be made is returned. Throttling must be
+ * applied on a per-slot basis so that a successful read from one slot does
+ * not reset the throttling state of any other slot.
*
* Service status return:
*
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp
index bb99ae4..46cba93 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test.cpp
@@ -48,6 +48,13 @@
virtual void SetUp() override {
wifi_instance_name_ = std::get<0>(GetParam());
hostapd_instance_name_ = std::get<1>(GetParam());
+
+ // Disable Wi-Fi framework to avoid interference
+ isWifiEnabled_ = isWifiFrameworkEnabled();
+ isScanAlwaysEnabled_ = isWifiScanAlwaysAvailable();
+ toggleWifiFramework(false);
+ toggleWifiScanAlwaysAvailable(false);
+
stopSupplicantIfNeeded(wifi_instance_name_);
startHostapdAndWaitForHidlService(wifi_instance_name_,
hostapd_instance_name_);
@@ -58,14 +65,21 @@
virtual void TearDown() override {
HIDL_INVOKE_VOID_WITHOUT_ARGUMENTS(hostapd_, terminate);
stopHostapd(wifi_instance_name_);
+
+ // Restore Wi-Fi framework state
+ toggleWifiFramework(isWifiEnabled_);
+ toggleWifiScanAlwaysAvailable(isScanAlwaysEnabled_);
}
protected:
- std::string getPrimaryWlanIfaceName() {
+ bool isWifiEnabled_ = false;
+ bool isScanAlwaysEnabled_ = false;
+
+ std::string getPrimaryWlanIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
property_get("wifi.interface", buffer.data(), "wlan0");
return buffer.data();
- }
+ }
IHostapd::IfaceParams getIfaceParamsWithAcs() {
IHostapd::IfaceParams iface_params;
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
index 56f285d..4c452fb 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
@@ -98,3 +98,24 @@
::android::hardware::wifi::hostapd::V1_1::IHostapd::castFrom(hostapd);
return hostapd_1_1.get() != nullptr;
}
+
+void toggleWifiFramework(bool enable) {
+ std::string cmd = "/system/bin/cmd wifi set-wifi-enabled ";
+ cmd += enable ? "enabled" : "disabled";
+ testing::checkSubstringInCommandOutput(cmd.c_str(), "X");
+}
+
+void toggleWifiScanAlwaysAvailable(bool enable) {
+ std::string cmd = "/system/bin/cmd wifi set-scan-always-available ";
+ cmd += enable ? "enabled" : "disabled";
+ testing::checkSubstringInCommandOutput(cmd.c_str(), "X");
+}
+
+bool isWifiFrameworkEnabled() {
+ return testing::checkSubstringInCommandOutput("/system/bin/cmd wifi status", "Wifi is enabled");
+}
+
+bool isWifiScanAlwaysAvailable() {
+ return testing::checkSubstringInCommandOutput("/system/bin/cmd wifi status",
+ "Wifi scanning is always available");
+}
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
index 893de1e..aa34c9a 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.h
@@ -17,14 +17,17 @@
#ifndef HOSTAPD_HIDL_TEST_UTILS_H
#define HOSTAPD_HIDL_TEST_UTILS_H
+#include <VtsCoreUtil.h>
#include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
#include <android/hardware/wifi/hostapd/1.1/IHostapd.h>
// Used to stop the android wifi framework before every test.
-void stopWifiFramework(const std::string& instance_name);
-void startWifiFramework(const std::string& instance_name);
void stopSupplicantIfNeeded(const std::string& instance_name);
void stopHostapd(const std::string& instance_name);
+void toggleWifiFramework(bool enable);
+void toggleWifiScanAlwaysAvailable(bool enable);
+bool isWifiFrameworkEnabled();
+bool isWifiScanAlwaysAvailable();
// Used to configure the chip, driver and start wpa_hostapd before every
// test.
void startHostapdAndWaitForHidlService(
diff --git a/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h b/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h
index feee2c8..50a38d3 100644
--- a/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h
+++ b/wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h
@@ -63,7 +63,7 @@
LOG(ERROR) << "Unable to " << (enable ? "start" : "stop") << " supplicant";
}
-void toggleWifiFramework(bool enable) {
+void toggleWifiFrameworkAndScan(bool enable) {
if (enable) {
std::system("svc wifi enable");
std::system("cmd wifi set-scan-always-available enabled");
@@ -89,7 +89,7 @@
* any other clients to the HALs during testing.
*/
void disableHalsAndFramework() {
- toggleWifiFramework(false);
+ toggleWifiFrameworkAndScan(false);
stopHostapd();
stopVendorHal();
@@ -110,7 +110,7 @@
}
void startWifiFramework() {
- toggleWifiFramework(true);
+ toggleWifiFrameworkAndScan(true);
}
std::string setupApIfaceAndGetName(bool isBridged) {