Merge "Fix crash in SthalCli" 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..85e4e24 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -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);
@@ -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..3117134 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -517,7 +517,7 @@
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 +550,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 +619,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();
}
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..ccf7cfc 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"
@@ -144,28 +145,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 +421,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 +523,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 +558,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 +582,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;
@@ -1258,11 +1296,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 +1305,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 +1824,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());
}
}
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..5774db5
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/include/EvsCamera.h
@@ -0,0 +1,138 @@
+/*
+ * 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. (static_cast<size_t>(-1), 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};
+};
+
+} // 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..c7b9e0f 100644
--- a/automotive/evs/aidl/impl/default/include/EvsMockCamera.h
+++ b/automotive/evs/aidl/impl/default/include/EvsMockCamera.h
@@ -17,8 +17,8 @@
#pragma once
#include "ConfigManager.h"
+#include "EvsCameraBase.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>
@@ -36,14 +36,7 @@
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<>.
- private:
- struct Sigil {
- explicit Sigil() = default;
- };
-
+class EvsMockCamera : public EvsCameraBase {
public:
// Methods from ::android::hardware::automotive::evs::IEvsCamera follow.
ndk::ScopedAStatus doneWithFrame(const std::vector<evs::BufferDesc>& buffers) override;
@@ -81,7 +74,9 @@
EvsMockCamera& operator=(const EvsMockCamera&) = delete;
virtual ~EvsMockCamera() override;
- void shutdown();
+
+ // Methods from EvsCameraBase follow.
+ void shutdown() override;
const evs::CameraDesc& getDesc() { return mDescription; }
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..208a1a4
--- /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 {static_cast<std::size_t>(-1), 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/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..3cbc04a
--- /dev/null
+++ b/automotive/evs/aidl/impl/default/tests/EvsCameraBufferTest.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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_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_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_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..70dba30 100644
--- a/automotive/remoteaccess/hal/default/Android.bp
+++ b/automotive/remoteaccess/hal/default/Android.bp
@@ -47,9 +47,20 @@
],
}
+// TODO(b/295393732): remove this once we finish the migration from V1 to V2.
cc_binary {
name: "android.hardware.automotive.remoteaccess@V1-default-service",
defaults: ["remote-access-hal-defaults"],
+ vintf_fragments: ["remoteaccess-default-service-v1.xml"],
+ init_rc: ["remoteaccess-default-service-v1.rc"],
+ cflags: [
+ "-DGRPC_SERVICE_ADDRESS=\"10.0.2.2:50051\"",
+ ],
+}
+
+cc_binary {
+ 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"],
cflags: [
@@ -57,9 +68,21 @@
],
}
+// TODO(b/295393732): remove this once we finish the migration from V1 to V2.
cc_binary {
name: "android.hardware.automotive.remoteaccess@V1-tcu-test-service",
defaults: ["remote-access-hal-defaults"],
+ vintf_fragments: ["remoteaccess-default-service-v1.xml"],
+ init_rc: ["remoteaccess-tcu-test-service-v1.rc"],
+ cflags: [
+ "-DGRPC_SERVICE_ADDRESS=\"10.10.10.1:50051\"",
+ "-DGRPC_SERVICE_IFNAME=\"eth1\"",
+ ],
+}
+
+cc_binary {
+ 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"],
cflags: [
@@ -77,7 +100,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 +122,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-v1.rc b/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.rc
new file mode 100644
index 0000000..b7a9cdc
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.rc
@@ -0,0 +1,4 @@
+service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-default-service
+ class hal
+ user vehicle_network
+ group system inet
diff --git a/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.xml b/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.xml
new file mode 100644
index 0000000..d050a1b
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/remoteaccess-default-service-v1.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.automotive.remoteaccess</name>
+ <version>1</version>
+ <fqname>IRemoteAccess/default</fqname>
+ </hal>
+</manifest>
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-v1.rc b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service-v1.rc
new file mode 100644
index 0000000..59315eb
--- /dev/null
+++ b/automotive/remoteaccess/hal/default/remoteaccess-tcu-test-service-v1.rc
@@ -0,0 +1,5 @@
+service vendor.remoteaccess-default /vendor/bin/hw/android.hardware.automotive.remoteaccess@V1-tcu-test-service
+ class hal
+ user vehicle_network
+ group system inet
+ capabilities NET_RAW
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/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/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/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/proto/Android.bp b/automotive/vehicle/proto/Android.bp
index 683f128..7b98540 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__",
+ "//device/google/sdv/sdv_ivi_cf:__subpackages__",
],
vendor: true,
host_supported: true,
diff --git a/boot/1.1/default/Android.bp b/boot/1.1/default/Android.bp
index 0b0a5b7..e7a8d6e 100644
--- a/boot/1.1/default/Android.bp
+++ b/boot/1.1/default/Android.bp
@@ -20,6 +20,7 @@
srcs: ["BootControl.cpp"],
shared_libs: [
+ "libbase",
"liblog",
"libhidlbase",
"libhardware",
diff --git a/boot/1.1/default/boot_control/Android.bp b/boot/1.1/default/boot_control/Android.bp
index 6aa30c2..d0dcb59 100644
--- a/boot/1.1/default/boot_control/Android.bp
+++ b/boot/1.1/default/boot_control/Android.bp
@@ -35,14 +35,13 @@
],
shared_libs: [
- "android.hardware.boot@1.1",
- "libbase",
"liblog",
],
static_libs: [
"libbootloader_message",
"libfstab",
],
+
}
cc_library_static {
@@ -52,7 +51,13 @@
recovery_available: true,
vendor_available: true,
- srcs: ["libboot_control.cpp"],
+ srcs: [
+ "libboot_control.cpp",
+ ],
+ static_libs: [
+ "android.hardware.boot@1.1",
+ "libbase",
+ ],
}
cc_library_shared {
@@ -67,6 +72,8 @@
"libboot_control",
],
shared_libs: [
+ "android.hardware.boot@1.1",
+ "libbase",
"libhardware",
],
}
diff --git a/boot/1.2/default/Android.bp b/boot/1.2/default/Android.bp
index 4e1c35e..f1e9c34 100644
--- a/boot/1.2/default/Android.bp
+++ b/boot/1.2/default/Android.bp
@@ -20,6 +20,7 @@
srcs: ["BootControl.cpp"],
shared_libs: [
+ "libbase",
"liblog",
"libhidlbase",
"libhardware",
diff --git a/boot/aidl/default/Android.bp b/boot/aidl/default/Android.bp
index dcb40db..c1d3c57 100644
--- a/boot/aidl/default/Android.bp
+++ b/boot/aidl/default/Android.bp
@@ -27,7 +27,39 @@
name: "android.hardware.boot-service_common",
relative_install_path: "hw",
defaults: ["libboot_control_defaults"],
+ srcs: [
+ "main.cpp",
+ "BootControl.cpp",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.boot-service.default",
+ defaults: ["android.hardware.boot-service_common"],
+ vendor: true,
+
+ stl: "c++_static",
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ ],
+ static_libs: [
+ "android.hardware.boot@1.1",
+ "android.hardware.boot-V1-ndk",
+ "libbase",
+ "libboot_control",
+ ],
+
+ installable: false, // installed in APEX
+}
+
+cc_binary {
+ name: "android.hardware.boot-service.default_recovery",
+ defaults: ["android.hardware.boot-service_common"],
+ init_rc: ["android.hardware.boot-service.default_recovery.rc"],
vintf_fragments: ["android.hardware.boot-service.default.xml"],
+ recovery: true,
+
shared_libs: [
"libbase",
"libbinder_ndk",
@@ -37,19 +69,35 @@
static_libs: [
"libboot_control",
],
- srcs: ["main.cpp", "BootControl.cpp"],
}
-cc_binary {
- name: "android.hardware.boot-service.default",
- defaults: ["android.hardware.boot-service_common"],
- init_rc: ["android.hardware.boot-service.default.rc"],
+prebuilt_etc {
+ name: "android.hardware.boot-service.default.rc",
+ src: "android.hardware.boot-service.default.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "android.hardware.boot-service.default.xml",
+ src: "android.hardware.boot-service.default.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
+
+apex {
+ name: "com.android.hardware.boot",
vendor: true,
-}
+ manifest: "apex_manifest.json",
+ file_contexts: "apex_file_contexts",
+ key: "com.android.hardware.key",
+ certificate: ":com.android.hardware.certificate",
+ updatable: false,
-cc_binary {
- name: "android.hardware.boot-service.default_recovery",
- defaults: ["android.hardware.boot-service_common"],
- init_rc: ["android.hardware.boot-service.default_recovery.rc"],
- recovery: true,
+ binaries: [
+ "android.hardware.boot-service.default",
+ ],
+ prebuilts: [
+ "android.hardware.boot-service.default.rc",
+ "android.hardware.boot-service.default.xml",
+ ],
}
diff --git a/boot/aidl/default/android.hardware.boot-service.default.rc b/boot/aidl/default/android.hardware.boot-service.default.rc
index 589f803..5090e2c 100644
--- a/boot/aidl/default/android.hardware.boot-service.default.rc
+++ b/boot/aidl/default/android.hardware.boot-service.default.rc
@@ -1,4 +1,4 @@
-service vendor.boot-default /vendor/bin/hw/android.hardware.boot-service.default
+service vendor.boot-default /apex/com.android.hardware.boot/bin/hw/android.hardware.boot-service.default
class early_hal
user root
group root
diff --git a/boot/aidl/default/apex_file_contexts b/boot/aidl/default/apex_file_contexts
new file mode 100644
index 0000000..bf03585
--- /dev/null
+++ b/boot/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\.boot-service\.default u:object_r:hal_bootctl_default_exec:s0
diff --git a/boot/aidl/default/apex_manifest.json b/boot/aidl/default/apex_manifest.json
new file mode 100644
index 0000000..92661c9
--- /dev/null
+++ b/boot/aidl/default/apex_manifest.json
@@ -0,0 +1,5 @@
+{
+ "name": "com.android.hardware.boot",
+ "version": 1,
+ "vendorBootstrap": true
+}
\ No newline at end of file
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/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/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/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/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/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/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/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.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/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/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) {