Merge "Add Inter-Signal Bias fields"
diff --git a/automotive/audiocontrol/2.0/Android.bp b/automotive/audiocontrol/2.0/Android.bp
new file mode 100644
index 0000000..2a9f849
--- /dev/null
+++ b/automotive/audiocontrol/2.0/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.automotive.audiocontrol@2.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IAudioControl.hal",
+ "ICloseHandle.hal",
+ "IFocusListener.hal",
+ ],
+ interfaces: [
+ "android.hidl.base@1.0",
+ "android.hardware.audio.common@6.0",
+ ],
+ gen_java: true,
+}
diff --git a/automotive/audiocontrol/2.0/IAudioControl.hal b/automotive/audiocontrol/2.0/IAudioControl.hal
new file mode 100644
index 0000000..1073498
--- /dev/null
+++ b/automotive/audiocontrol/2.0/IAudioControl.hal
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+import ICloseHandle;
+import IFocusListener;
+import android.hardware.audio.common@6.0::AudioUsage;
+
+/**
+ * Interacts with the car's audio subsystem to manage audio sources and volumes
+ */
+interface IAudioControl {
+ /**
+ * Registers focus listener to be used by HAL for requesting and abandoning audio focus.
+ *
+ * It is expected that there will only ever be a single focus listener registered. If the
+ * observer dies, the HAL implementation must unregister observer automatically. If called when
+ * a listener is already registered, the existing one should be unregistered and replaced with
+ * the new listener.
+ *
+ * @param listener the listener interface
+ * @return closeHandle A handle to unregister observer.
+ */
+ registerFocusListener(IFocusListener listener) generates (ICloseHandle closeHandle);
+
+ /**
+ * Notifies HAL of changes in audio focus status for focuses requested or abandoned by the HAL.
+ *
+ * This will be called in response to IFocusListener's requestAudioFocus and
+ * abandonAudioFocus, as well as part of any change in focus being held by the HAL due focus
+ * request from other activities or services.
+ *
+ * The HAL is not required to wait for an callback of AUDIOFOCUS_GAIN before playing audio, nor
+ * is it required to stop playing audio in the event of a AUDIOFOCUS_LOSS callback is received.
+ *
+ * @param usage The audio usage associated with the focus change {@code AttributeUsage}
+ * @param zoneId The identifier for the audio zone that the HAL is playing the stream in
+ * @param focusChange the AudioFocusChange that has occurred
+ */
+ oneway onAudioFocusChange(bitfield<AudioUsage> usage, int32_t zoneId,
+ bitfield<AudioFocusChange> focusChange);
+
+ /**
+ * Control the right/left balance setting of the car speakers.
+ *
+ * This is intended to shift the speaker volume toward the right (+) or left (-) side of
+ * the car. 0.0 means "centered". +1.0 means fully right. -1.0 means fully left.
+ *
+ * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
+ * range.
+ */
+ oneway setBalanceTowardRight(float value);
+
+ /**
+ * Control the fore/aft fade setting of the car speakers.
+ *
+ * This is intended to shift the speaker volume toward the front (+) or back (-) of the car.
+ * 0.0 means "centered". +1.0 means fully forward. -1.0 means fully rearward.
+ *
+ * A value outside the range -1 to 1 must be clamped by the implementation to the -1 to 1
+ * range.
+ */
+ oneway setFadeTowardFront(float value);
+};
diff --git a/automotive/audiocontrol/2.0/ICloseHandle.hal b/automotive/audiocontrol/2.0/ICloseHandle.hal
new file mode 100644
index 0000000..537af6d
--- /dev/null
+++ b/automotive/audiocontrol/2.0/ICloseHandle.hal
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+/**
+ * Represents a generic close handle to remove a callback that doesn't need
+ * active interface.
+ *
+ * When close() is called OR when the interface is released, the underlying
+ * resources must be freed.
+ */
+interface ICloseHandle {
+ /**
+ * Closes the handle.
+ *
+ * The call must not fail and must be issued by the client at most once.
+ * Otherwise, the server must ignore subsequent calls.
+ */
+ close();
+};
diff --git a/automotive/audiocontrol/2.0/IFocusListener.hal b/automotive/audiocontrol/2.0/IFocusListener.hal
new file mode 100644
index 0000000..4fd5ef0
--- /dev/null
+++ b/automotive/audiocontrol/2.0/IFocusListener.hal
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+import android.hardware.audio.common@6.0::AudioUsage;
+
+/**
+ * Callback interface for audio focus listener.
+ *
+ * For typical configuration, the listener the car audio service.
+ */
+interface IFocusListener {
+ /**
+ * Called whenever HAL is requesting focus as it is starting to play audio of a given usage in a
+ * specified zone.
+ *
+ * In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This
+ * interaction is oneway to avoid blocking HAL so that it is not required to wait for a response
+ * before playing audio.
+ *
+ * @param usage The audio usage associated with the focus request {@code AttributeUsage}
+ * @param zoneId The identifier for the audio zone where the HAL is requesting focus
+ * @param focusGain The AudioFocusChange associated with this request. Should be one of the
+ * following: GAIN, GAIN_TRANSIENT, GAIN_TRANSIENT_MAY_DUCK, GAIN_TRANSIENT_EXCLUSIVE.
+ */
+ oneway requestAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId,
+ bitfield<AudioFocusChange> focusGain);
+
+ /**
+ * Called whenever HAL is abandoning focus as it is finished playing audio of a given usage in a
+ * specific zone.
+ *
+ * In response, IAudioControl#onAudioFocusChange will be called with focusChange status. This
+ * interaction is oneway to avoid blocking HAL so that it is not required to wait for a response
+ * before stopping audio playback.
+ *
+ * @param usage The audio usage for which the HAL is abandoning focus {@code AttributeUsage}
+ * @param zoneId The identifier for the audio zone that the HAL abandoning focus
+ */
+ oneway abandonAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId);
+};
diff --git a/automotive/audiocontrol/2.0/default/Android.bp b/automotive/audiocontrol/2.0/default/Android.bp
new file mode 100644
index 0000000..44ad028
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+ name: "android.hardware.automotive.audiocontrol@2.0-service",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "AudioControl.cpp",
+ "service.cpp",
+ "CloseHandle.cpp",
+ ],
+ init_rc: ["android.hardware.automotive.audiocontrol@2.0-service.rc"],
+
+ shared_libs: [
+ "android.hardware.automotive.audiocontrol@2.0",
+ "libbase",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ vintf_fragments: ["audiocontrol2_manifest.xml"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/automotive/audiocontrol/2.0/default/AudioControl.cpp b/automotive/audiocontrol/2.0/default/AudioControl.cpp
new file mode 100644
index 0000000..6505e34
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/AudioControl.cpp
@@ -0,0 +1,60 @@
+#include "AudioControl.h"
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "CloseHandle.h"
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+AudioControl::AudioControl() {}
+
+Return<sp<ICloseHandle>> AudioControl::registerFocusListener(const sp<IFocusListener>& listener) {
+ LOG(DEBUG) << "registering focus listener";
+ sp<ICloseHandle> closeHandle(nullptr);
+
+ if (listener) {
+ mFocusListener = listener;
+
+ closeHandle = new CloseHandle([this, listener]() {
+ if (mFocusListener == listener) {
+ mFocusListener = nullptr;
+ }
+ });
+ } else {
+ LOG(ERROR) << "Unexpected nullptr for listener resulting in no-op.";
+ }
+
+ return closeHandle;
+}
+
+Return<void> AudioControl::setBalanceTowardRight(float value) {
+ // For completeness, lets bounds check the input...
+ if (isValidValue(value)) {
+ LOG(ERROR) << "Balance value out of range -1 to 1 at " << value;
+ } else {
+ // Just log in this default mock implementation
+ LOG(INFO) << "Balance set to " << value;
+ }
+ return Void();
+}
+
+Return<void> AudioControl::setFadeTowardFront(float value) {
+ // For completeness, lets bounds check the input...
+ if (isValidValue(value)) {
+ LOG(ERROR) << "Fader value out of range -1 to 1 at " << value;
+ } else {
+ // Just log in this default mock implementation
+ LOG(INFO) << "Fader set to " << value;
+ }
+ return Void();
+}
+
+Return<void> AudioControl::onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId,
+ hidl_bitfield<AudioFocusChange> focusChange) {
+ LOG(INFO) << "Focus changed: " << static_cast<int>(focusChange) << " for usage "
+ << static_cast<int>(usage) << " in zone " << zoneId;
+ return Void();
+}
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/AudioControl.h b/automotive/audiocontrol/2.0/default/AudioControl.h
new file mode 100644
index 0000000..475a693
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/AudioControl.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
+#define ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
+
+#include <android/hardware/audio/common/6.0/types.h>
+#include <android/hardware/automotive/audiocontrol/2.0/IAudioControl.h>
+#include <android/hardware/automotive/audiocontrol/2.0/ICloseHandle.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+using android::hardware::audio::common::V6_0::AudioUsage;
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+class AudioControl : public IAudioControl {
+ public:
+ // Methods from ::android::hardware::automotive::audiocontrol::V2_0::IAudioControl follow.
+ Return<sp<ICloseHandle>> registerFocusListener(const sp<IFocusListener>& listener);
+ Return<void> onAudioFocusChange(hidl_bitfield<AudioUsage> usage, int zoneId,
+ hidl_bitfield<AudioFocusChange> focusChange);
+ Return<void> setBalanceTowardRight(float value) override;
+ Return<void> setFadeTowardFront(float value) override;
+
+ // Implementation details
+ AudioControl();
+
+ private:
+ sp<IFocusListener> mFocusListener;
+ static bool isValidValue(float value) { return (value > 1.0f) || (value < -1.0f); }
+};
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
+
+#endif // ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_V2_0_AUDIOCONTROL_H
diff --git a/automotive/audiocontrol/2.0/default/CloseHandle.cpp b/automotive/audiocontrol/2.0/default/CloseHandle.cpp
new file mode 100644
index 0000000..bc47931
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/CloseHandle.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CloseHandle.h"
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+CloseHandle::CloseHandle(Callback callback) : mCallback(callback) {}
+
+CloseHandle::~CloseHandle() {
+ close();
+}
+
+Return<void> CloseHandle::close() {
+ const auto wasClosed = mIsClosed.exchange(true);
+ if (wasClosed) return {};
+
+ if (mCallback) mCallback();
+ return {};
+}
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/CloseHandle.h b/automotive/audiocontrol/2.0/default/CloseHandle.h
new file mode 100644
index 0000000..6caf0bf
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/CloseHandle.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/macros.h>
+#include <android/hardware/automotive/audiocontrol/2.0/ICloseHandle.h>
+
+namespace android::hardware::automotive::audiocontrol::V2_0::implementation {
+
+/** Generic ICloseHandle implementation ignoring double-close events. */
+class CloseHandle : public ICloseHandle {
+ public:
+ using Callback = std::function<void()>;
+
+ /**
+ * Create a handle with a callback.
+ *
+ * The callback is guaranteed to be called exactly once.
+ *
+ * \param callback Called on the first close() call, or on destruction of the handle
+ */
+ CloseHandle(Callback callback = nullptr);
+ virtual ~CloseHandle();
+
+ Return<void> close() override;
+
+ private:
+ const Callback mCallback;
+ std::atomic<bool> mIsClosed = false;
+
+ DISALLOW_COPY_AND_ASSIGN(CloseHandle);
+};
+
+} // namespace android::hardware::automotive::audiocontrol::V2_0::implementation
diff --git a/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc b/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc
new file mode 100644
index 0000000..81c9be4
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/android.hardware.automotive.audiocontrol@2.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.audiocontrol-hal-2.0 /vendor/bin/hw/android.hardware.automotive.audiocontrol@2.0-service
+ class hal
+ user audioserver
+ group system
diff --git a/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml b/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml
new file mode 100644
index 0000000..42d23ed
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/audiocontrol2_manifest.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.automotive.audiocontrol</name>
+ <transport>hwbinder</transport>
+ <version>2.0</version>
+ <interface>
+ <name>IAudioControl</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
\ No newline at end of file
diff --git a/automotive/audiocontrol/2.0/default/service.cpp b/automotive/audiocontrol/2.0/default/service.cpp
new file mode 100644
index 0000000..dcc46c3
--- /dev/null
+++ b/automotive/audiocontrol/2.0/default/service.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "AudioControl.h"
+
+// libhidl:
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+
+// Generated HIDL files
+using android::hardware::automotive::audiocontrol::V2_0::IAudioControl;
+
+// The namespace in which all our implementation code lives
+using namespace android::hardware::automotive::audiocontrol::V2_0::implementation;
+using namespace android;
+
+// Main service entry point
+int main() {
+ // Create an instance of our service class
+ android::sp<IAudioControl> service = new AudioControl();
+ configureRpcThreadpool(1, true /*callerWillJoin*/);
+
+ if (service->registerAsService() != OK) {
+ LOG(ERROR) << "registerAsService failed";
+ return 1;
+ }
+
+ // Join (forever) the thread pool we created for the service above
+ joinRpcThreadpool();
+
+ // We don't ever actually expect to return, so return an error if we do get here
+ return 2;
+}
\ No newline at end of file
diff --git a/automotive/audiocontrol/2.0/types.hal b/automotive/audiocontrol/2.0/types.hal
new file mode 100644
index 0000000..65b0988
--- /dev/null
+++ b/automotive/audiocontrol/2.0/types.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.automotive.audiocontrol@2.0;
+
+/**
+ * Changes in audio focus that can be experienced
+ */
+enum AudioFocusChange : uint32_t {
+ NONE = 0,
+ GAIN = 1,
+ GAIN_TRANSIENT = 2,
+ GAIN_TRANSIENT_MAY_DUCK = 3,
+ GAIN_TRANSIENT_EXCLUSIVE = 4,
+ LOSS = -1 * GAIN,
+ LOSS_TRANSIENT = -1 * GAIN_TRANSIENT,
+ LOSS_TRANSIENT_CAN_DUCK = -1 * GAIN_TRANSIENT_MAY_DUCK,
+};
diff --git a/automotive/audiocontrol/2.0/vts/functional/Android.bp b/automotive/audiocontrol/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..520b042
--- /dev/null
+++ b/automotive/audiocontrol/2.0/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalAudioControlV2_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalAudioControlV2_0TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.automotive.audiocontrol@2.0",
+ "libgmock",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
new file mode 100644
index 0000000..0c10664
--- /dev/null
+++ b/automotive/audiocontrol/2.0/vts/functional/VtsHalAudioControlV2_0TargetTest.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalAudioControlTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/ProcessState.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include <android/hardware/audio/common/6.0/types.h>
+#include <android/hardware/automotive/audiocontrol/2.0/IAudioControl.h>
+#include <android/hardware/automotive/audiocontrol/2.0/types.h>
+#include <android/log.h>
+
+using namespace ::android::hardware::automotive::audiocontrol::V2_0;
+using ::android::sp;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_enum_range;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V6_0::AudioUsage;
+
+// The main test class for the automotive AudioControl HAL
+class CarAudioControlHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ // Make sure we can connect to the driver
+ pAudioControl = IAudioControl::getService(GetParam());
+ ASSERT_NE(pAudioControl.get(), nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ protected:
+ sp<IAudioControl> pAudioControl; // Every test needs access to the service
+};
+
+//
+// Tests start here...
+//
+
+/*
+ * Fader exercise test. Note that only a subjective observer could determine if the
+ * fader actually works. The only thing we can do is exercise the HAL and if the HAL crashes,
+ * we _might_ get a test failure if that breaks the connection to the driver.
+ */
+TEST_P(CarAudioControlHidlTest, FaderExercise) {
+ ALOGI("Fader exercise test (silent)");
+
+ // Set the fader all the way to the back
+ pAudioControl->setFadeTowardFront(-1.0f);
+
+ // Set the fader all the way to the front
+ pAudioControl->setFadeTowardFront(1.0f);
+
+ // Set the fader part way toward the back
+ pAudioControl->setFadeTowardFront(-0.333f);
+
+ // Set the fader to a out of bounds value (driver should clamp)
+ pAudioControl->setFadeTowardFront(99999.9f);
+
+ // Set the fader back to the middle
+ pAudioControl->setFadeTowardFront(0.0f);
+}
+
+/*
+ * Balance exercise test.
+ */
+TEST_P(CarAudioControlHidlTest, BalanceExercise) {
+ ALOGI("Balance exercise test (silent)");
+
+ // Set the balance all the way to the left
+ pAudioControl->setBalanceTowardRight(-1.0f);
+
+ // Set the balance all the way to the right
+ pAudioControl->setBalanceTowardRight(1.0f);
+
+ // Set the balance part way toward the left
+ pAudioControl->setBalanceTowardRight(-0.333f);
+
+ // Set the balance to a out of bounds value (driver should clamp)
+ pAudioControl->setBalanceTowardRight(99999.9f);
+
+ // Set the balance back to the middle
+ pAudioControl->setBalanceTowardRight(0.0f);
+}
+
+struct FocusListenerMock : public IFocusListener {
+ MOCK_METHOD(Return<void>, requestAudioFocus,
+ (hidl_bitfield<AudioUsage> usage, int zoneId,
+ hidl_bitfield<AudioFocusChange> focusGain));
+ MOCK_METHOD(Return<void>, abandonAudioFocus, (hidl_bitfield<AudioUsage> usage, int zoneId));
+};
+
+/*
+ * Test focus listener registration.
+ *
+ * Verifies that:
+ * - registerFocusListener succeeds;
+ * - registering a second listener succeeds in replacing the first;
+ * - closing handle does not crash;
+ */
+TEST_P(CarAudioControlHidlTest, FocusListenerRegistration) {
+ ALOGI("Focus listener test");
+
+ sp<FocusListenerMock> listener = new FocusListenerMock();
+
+ auto hidlResult = pAudioControl->registerFocusListener(listener);
+ ASSERT_TRUE(hidlResult.isOk());
+
+ sp<FocusListenerMock> listener2 = new FocusListenerMock();
+
+ auto hidlResult2 = pAudioControl->registerFocusListener(listener2);
+ ASSERT_TRUE(hidlResult2.isOk());
+
+ const sp<ICloseHandle>& closeHandle = hidlResult2;
+ closeHandle->close();
+};
+
+TEST_P(CarAudioControlHidlTest, FocusChangeExercise) {
+ ALOGI("Focus Change test");
+
+ pAudioControl->onAudioFocusChange(AudioUsage::MEDIA | 0, 0,
+ AudioFocusChange::GAIN_TRANSIENT | 0);
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, CarAudioControlHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAudioControl::descriptor)),
+ android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/biometrics/face/1.1/Android.bp b/biometrics/face/1.1/Android.bp
new file mode 100644
index 0000000..2206597
--- /dev/null
+++ b/biometrics/face/1.1/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.biometrics.face@1.1",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IBiometricsFace.hal",
+ ],
+ interfaces: [
+ "android.hardware.biometrics.face@1.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/biometrics/face/1.1/IBiometricsFace.hal b/biometrics/face/1.1/IBiometricsFace.hal
new file mode 100644
index 0000000..975001f
--- /dev/null
+++ b/biometrics/face/1.1/IBiometricsFace.hal
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 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.biometrics.face@1.1;
+import @1.0::IBiometricsFace;
+import @1.0::Status;
+import @1.0::Feature;
+
+/**
+ * The HAL interface for biometric face authentication.
+ */
+interface IBiometricsFace extends @1.0::IBiometricsFace {
+ /**
+ * Enrolls a user's face for a remote client, for example Android Auto.
+ *
+ * The HAL implementation is responsible for creating a secure communication
+ * channel and receiving the enrollment images from a mobile device with
+ * face authentication hardware.
+ *
+ * Note that the Hardware Authentication Token must be valid for the
+ * duration of enrollment and thus should be explicitly invalidated by a
+ * call to revokeChallenge() when enrollment is complete, to reduce the
+ * window of opportunity to re-use the challenge and HAT. For example,
+ * Settings calls generateChallenge() once to allow the user to enroll one
+ * or more faces or toggle secure settings without having to re-enter the
+ * PIN/pattern/password. Once the user completes the operation, Settings
+ * invokes revokeChallenge() to close the transaction. If the HAT is expired,
+ * the implementation must invoke onError with UNABLE_TO_PROCESS.
+ *
+ * Requirements for using this API:
+ * - Mobile devices MUST NOT delegate enrollment to another device by calling
+ * this API. This feature is intended only to allow enrollment on devices
+ * where it is impossible to enroll locally on the device.
+ * - The path MUST be protected by a secret key with rollback protection.
+ * - Synchronizing between devices MUST be accomplished by having both
+ * devices agree on a secret PIN entered by the user (similar to BT
+ * pairing procedure) and use a salted version of that PIN plus other secret
+ * to encrypt traffic.
+ * - All communication to/from the remote device MUST be encrypted and signed
+ * to prevent image injection and other man-in-the-middle type attacks.
+ * - generateChallenge() and revokeChallenge() MUST be implemented on both
+ * remote and local host (e.g. hash the result of the remote host with a
+ * local secret before responding to the API call) and any transmission of
+ * the challenge between hosts MUST be signed to prevent man-in-the-middle
+ * attacks.
+ * - In the event of a lost connection, the result of the last
+ * generateChallenge() MUST be invalidated and the process started over.
+ * - Both the remote and local host MUST honor the timeout and invalidate the
+ * challenge.
+ *
+ * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+ * method.
+ *
+ * @param hat A valid Hardware Authentication Token, generated as a result
+ * of a generateChallenge() challenge being wrapped by the gatekeeper
+ * after a successful strong authentication request.
+ * @param timeoutSec A timeout in seconds, after which this enroll
+ * attempt is cancelled. Note that the framework can continue
+ * enrollment by calling this again with a valid HAT. This timeout is
+ * expected to be used to limit power usage if the device becomes idle
+ * during enrollment. The implementation is expected to send
+ * ERROR_TIMEOUT if this happens.
+ * @param disabledFeatures A list of features to be disabled during
+ * enrollment. Note that all features are enabled by default.
+ * @return status The status of this method call.
+ */
+ enrollRemotely(vec<uint8_t> hat, uint32_t timeoutSec,
+ vec<Feature> disabledFeatures) generates (Status status);
+};
diff --git a/biometrics/face/1.1/vts/functional/Android.bp b/biometrics/face/1.1/vts/functional/Android.bp
new file mode 100644
index 0000000..ccbb399
--- /dev/null
+++ b/biometrics/face/1.1/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+ name: "VtsHalBiometricsFaceV1_1TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalBiometricsFaceV1_1TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.biometrics.face@1.0",
+ "android.hardware.biometrics.face@1.1",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
new file mode 100644
index 0000000..c2431c6
--- /dev/null
+++ b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "biometrics_face_hidl_hal_test"
+
+#include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
+#include <android/hardware/biometrics/face/1.1/IBiometricsFace.h>
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <chrono>
+#include <cstdint>
+#include <random>
+
+using android::sp;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo;
+using android::hardware::biometrics::face::V1_0::FaceError;
+using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
+using android::hardware::biometrics::face::V1_0::OptionalUint64;
+using android::hardware::biometrics::face::V1_0::Status;
+using android::hardware::biometrics::face::V1_1::IBiometricsFace;
+
+namespace {
+
+// Arbitrary, nonexistent userId
+constexpr uint32_t kUserId = 9;
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata";
+constexpr char kCallbackNameOnError[] = "onError";
+
+// Callback arguments that need to be captured for the tests.
+struct FaceCallbackArgs {
+ // The error passed to the last onError() callback.
+ FaceError error;
+
+ // The userId passed to the last callback.
+ int32_t userId;
+};
+
+// Test callback class for the BiometricsFace HAL.
+// The HAL will call these callback methods to notify about completed operations
+// or encountered errors.
+class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
+ public IBiometricsFaceClientCallback {
+ public:
+ Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { return Void(); }
+
+ Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
+ return Void();
+ }
+
+ Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
+ return Void();
+ }
+
+ Return<void> onError(uint64_t, int32_t userId, FaceError error, int32_t) override {
+ FaceCallbackArgs args = {};
+ args.error = error;
+ args.userId = userId;
+ NotifyFromCallback(kCallbackNameOnError, args);
+ return Void();
+ }
+
+ Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t) override { return Void(); }
+
+ Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
+ return Void();
+ }
+
+ Return<void> onLockoutChanged(uint64_t) override { return Void(); }
+};
+
+// Test class for the BiometricsFace HAL.
+class FaceHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ mService = IBiometricsFace::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ mCallback = new FaceCallback();
+ mCallback->SetWaitTimeoutDefault(kTimeout);
+ Return<void> ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) {
+ ASSERT_EQ(Status::OK, res.status);
+ // Makes sure the "deviceId" represented by "res.value" is not 0.
+ // 0 would mean the HIDL is not available.
+ ASSERT_NE(0UL, res.value);
+ });
+ ASSERT_TRUE(ret1.isOk());
+ Return<Status> ret2 = mService->setActiveUser(kUserId, kFacedataDir);
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret2));
+ }
+
+ void TearDown() override {}
+
+ sp<IBiometricsFace> mService;
+ sp<FaceCallback> mCallback;
+};
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) {
+ // Filling HAT with zeros
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
+
+ Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_P(FaceHidlTest, EnrollRemotelyGarbageHatTest) {
+ // Filling HAT with pseudorandom invalid data.
+ // Using default seed to make the test reproducible.
+ std::mt19937 gen(std::mt19937::default_seed);
+ std::uniform_int_distribution<uint8_t> dist;
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; ++i) {
+ token[i] = dist(gen);
+ }
+
+ Return<Status> ret = mService->enrollRemotely(token, kTimeoutSec, {});
+ ASSERT_EQ(Status::OK, static_cast<Status>(ret));
+
+ // onError should be called with a meaningful (nonzero) error.
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
+ EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
+}
+
+} // anonymous namespace
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, FaceHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/biometrics/fingerprint/2.2/Android.bp b/biometrics/fingerprint/2.2/Android.bp
new file mode 100644
index 0000000..6c769ac
--- /dev/null
+++ b/biometrics/fingerprint/2.2/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.biometrics.fingerprint@2.2",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "IBiometricsFingerprint.hal",
+ "IBiometricsFingerprintClientCallback.hal",
+ ],
+ interfaces: [
+ "android.hardware.biometrics.fingerprint@2.1",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal
new file mode 100644
index 0000000..0651034
--- /dev/null
+++ b/biometrics/fingerprint/2.2/IBiometricsFingerprint.hal
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint@2.2;
+
+import @2.1::IBiometricsFingerprint;
+import @2.1::RequestStatus;
+
+interface IBiometricsFingerprint extends @2.1::IBiometricsFingerprint {
+ /**
+ * Fingerprint enroll request:
+ * Switches the HAL state machine to collect and store a new fingerprint
+ * template. Switches back as soon as enroll is complete, signalled by
+ * (fingerprintMsg.type == FINGERPRINT_TEMPLATE_ENROLLING &&
+ * fingerprintMsg.data.enroll.samplesRemaining == 0)
+ * or after timeoutSec seconds.
+ * The fingerprint template must be assigned to the group gid.
+ *
+ * @param hat a valid Hardware Authentication Token (HAT), generated
+ * as a result of a preEnroll() call.
+ * @param gid a framework defined fingerprint set (group) id.
+ * @param timeoutSec a timeout in seconds.
+ * @param windowId optional ID of an illumination window for optical under
+ * display fingerprint sensors. Must contain a null pointer if not used.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ *
+ * A notify() function may be called with a more detailed error structure.
+ */
+ enroll_2_2(vec<uint8_t> hat, uint32_t gid, uint32_t timeoutSec, handle windowId)
+ generates (RequestStatus debugErrno);
+
+ /**
+ * Authenticates an operation identified by operationId
+ *
+ * @param operationId operation id.
+ * @param gid fingerprint group id.
+ * @param windowId optional ID of an illumination window for optical under
+ * display fingerprint sensors. Must contain a null pointer if not used.
+ *
+ * @return debugErrno is a value the framework logs in case it is not 0.
+ */
+ authenticate_2_2(uint64_t operationId, uint32_t gid, handle windowId)
+ generates (RequestStatus debugErrno);
+};
diff --git a/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal b/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal
new file mode 100644
index 0000000..14c2b12
--- /dev/null
+++ b/biometrics/fingerprint/2.2/IBiometricsFingerprintClientCallback.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint@2.2;
+
+import @2.1::IBiometricsFingerprintClientCallback;
+
+/*
+ * This HAL interface communicates asynchronous results from the
+ * fingerprint driver in response to user actions on the fingerprint sensor
+ */
+interface IBiometricsFingerprintClientCallback extends @2.1::IBiometricsFingerprintClientCallback {
+ /**
+ * Sent when a fingerprint image is acquired by the sensor
+ * @param deviceId the instance of this fingerprint device
+ * @param acquiredInfo a message about the quality of the acquired image
+ * @param vendorCode a vendor-specific message about the quality of the image. Only
+ * valid when acquiredInfo == ACQUIRED_VENDOR
+ */
+ oneway onAcquired_2_2(uint64_t deviceId, FingerprintAcquiredInfo acquiredInfo,
+ int32_t vendorCode);
+};
diff --git a/biometrics/fingerprint/2.2/types.hal b/biometrics/fingerprint/2.2/types.hal
new file mode 100644
index 0000000..2c1d3f3
--- /dev/null
+++ b/biometrics/fingerprint/2.2/types.hal
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.fingerprint@2.2;
+
+import @2.1::FingerprintAcquiredInfo;
+
+/**
+ * Fingerprint acquisition info is meant as feedback for the current operation.
+ * Anything but START and ACQUIRED_GOOD must be shown to the user as feedback on
+ * how to take action on the current operation. For example,
+ * ACQUIRED_IMAGER_DIRTY may be used to tell the user to clean the sensor if it
+ * is detected to be dirty.
+ * If this causes the current operation to fail, an additional ERROR_CANCELED
+ * must be sent to stop the operation in progress (e.g. enrollment).
+ * In general, these messages will result in a "Try again" message.
+ */
+enum FingerprintAcquiredInfo : @2.1::FingerprintAcquiredInfo {
+ /**
+ * This message represents the earliest message sent at the beginning of the
+ * authentication pipeline. It is expected to be used to measure latency. For
+ * example, in a camera-based authentication system it's expected to be sent
+ * prior to camera initialization. Note this should be sent whenever
+ * authentication is restarted (see IBiometricsFace#userActivity).
+ * The framework will measure latency based on the time between the last START
+ * message and the onAuthenticated callback.
+ */
+ START = 7,
+};
diff --git a/biometrics/fingerprint/2.2/vts/functional/Android.bp b/biometrics/fingerprint/2.2/vts/functional/Android.bp
new file mode 100644
index 0000000..496570c
--- /dev/null
+++ b/biometrics/fingerprint/2.2/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+cc_test {
+ name: "VtsHalBiometricsFingerprintV2_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalBiometricsFingerprintV2_2TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.biometrics.fingerprint@2.1",
+ "android.hardware.biometrics.fingerprint@2.2",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
new file mode 100644
index 0000000..50bd4ab
--- /dev/null
+++ b/biometrics/fingerprint/2.2/vts/functional/VtsHalBiometricsFingerprintV2_2TargetTest.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "fingerprint_hidl_hal_test"
+
+#include <VtsHalHidlTargetCallbackBase.h>
+#include <android-base/properties.h>
+#include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
+#include <android/hardware/biometrics/fingerprint/2.2/IBiometricsFingerprint.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+
+#include <cinttypes>
+#include <random>
+
+using android::sp;
+using android::base::GetUintProperty;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::biometrics::fingerprint::V2_1::FingerprintAcquiredInfo;
+using android::hardware::biometrics::fingerprint::V2_1::FingerprintError;
+using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
+using android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
+using android::hardware::biometrics::fingerprint::V2_2::IBiometricsFingerprint;
+
+namespace {
+
+constexpr uint32_t kTimeoutSec = 3;
+constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
+constexpr uint32_t kGroupId = 99;
+constexpr char kCallbackNameOnError[] = "onError";
+
+// Callback arguments that need to be captured for the tests.
+struct FingerprintCallbackArgs {
+ // The error passed to the last onError() callback.
+ FingerprintError error;
+
+ // The deviceId passed to the last callback.
+ uint64_t deviceId;
+};
+
+// Test callback class for the BiometricsFingerprint HAL.
+// The HAL will call these callback methods to notify about completed operations
+// or encountered errors.
+class FingerprintCallback : public ::testing::VtsHalHidlTargetCallbackBase<FingerprintCallbackArgs>,
+ public IBiometricsFingerprintClientCallback {
+ public:
+ Return<void> onEnrollResult(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+
+ Return<void> onAcquired(uint64_t, FingerprintAcquiredInfo, int32_t) override { return Void(); }
+
+ Return<void> onAuthenticated(uint64_t, uint32_t, uint32_t, const hidl_vec<uint8_t>&) override {
+ return Void();
+ }
+
+ Return<void> onError(uint64_t deviceId, FingerprintError error, int32_t) override {
+ FingerprintCallbackArgs args = {};
+ args.error = error;
+ args.deviceId = deviceId;
+ NotifyFromCallback(kCallbackNameOnError, args);
+ return Void();
+ }
+
+ Return<void> onRemoved(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+
+ Return<void> onEnumerate(uint64_t, uint32_t, uint32_t, uint32_t) override { return Void(); }
+};
+
+class FingerprintHidlTest : public ::testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ mService = IBiometricsFingerprint::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ mCallback = new FingerprintCallback();
+ mCallback->SetWaitTimeoutDefault(kTimeout);
+ Return<uint64_t> ret1 = mService->setNotify(mCallback);
+ ASSERT_NE(0UL, static_cast<uint64_t>(ret1));
+
+ /*
+ * Devices shipped from now on will instead store
+ * fingerprint data under /data/vendor_de/<user-id>/fpdata.
+ * Support for /data/vendor_de and /data/vendor_ce has been added to vold.
+ */
+
+ auto api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+ if (api_level == 0) {
+ api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+ }
+ ASSERT_NE(api_level, 0);
+
+ // 27 is the API number for O-MR1
+ string tmpDir;
+ if (api_level <= 27) {
+ tmpDir = "/data/system/users/0/fpdata/";
+ } else {
+ tmpDir = "/data/vendor_de/0/fpdata/";
+ }
+
+ Return<RequestStatus> res = mService->setActiveGroup(kGroupId, tmpDir);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
+ }
+
+ sp<IBiometricsFingerprint> mService;
+ sp<FingerprintCallback> mCallback;
+};
+
+// Enroll with an invalid (all zeroes) HAT should fail.
+TEST_P(FingerprintHidlTest, EnrollZeroHatTest) {
+ // Filling HAT with zeros
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; i++) {
+ token[i] = 0;
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<RequestStatus> ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(ret));
+
+ // At least one call to onError should occur
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error);
+}
+
+// Enroll with an invalid (null) HAT should fail.
+TEST_P(FingerprintHidlTest, EnrollGarbageHatTest) {
+ // Filling HAT with pseudorandom invalid data.
+ // Using default seed to make the test reproducible.
+ std::mt19937 gen(std::mt19937::default_seed);
+ std::uniform_int_distribution<uint8_t> dist;
+ hidl_vec<uint8_t> token(69);
+ for (size_t i = 0; i < 69; ++i) {
+ token[i] = dist(gen);
+ }
+
+ hidl_handle windowId = nullptr;
+ Return<RequestStatus> ret = mService->enroll_2_2(token, kGroupId, kTimeoutSec, windowId);
+ ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(ret));
+
+ // At least one call to onError should occur
+ auto res = mCallback->WaitForCallback(kCallbackNameOnError);
+ ASSERT_NE(FingerprintError::ERROR_NO_ERROR, res.args->error);
+}
+
+} // anonymous namespace
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, FingerprintHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+ IBiometricsFingerprint::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 14d9866..da10ef8 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -289,6 +289,13 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.light</name>
+ <interface>
+ <name>ILights</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.media.c2</name>
<version>1.0-1</version>
diff --git a/current.txt b/current.txt
index 71185c6..1d6171c 100644
--- a/current.txt
+++ b/current.txt
@@ -587,6 +587,7 @@
2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types
+9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback
b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
8eac60e1f724d141c71c69f06d4544acb720a55dfbbcd97fa01bb3d25ee4e2f5 android.hardware.neuralnetworks@1.0::types
@@ -656,7 +657,8 @@
65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer
d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice
4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback
-7d23020248194abbee8091cc624f39a5a6d7ccba338b172d5d2d3df0cceffbee android.hardware.neuralnetworks@1.3::IPreparedModel
+29e26e83399b69c7998b787bd30426dd5baa2da350effca76bbee1ba877355c9 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
+384fd9fd6e4d43ea11d407e52ea81da5242c3c5f4b458b8707d8feb652a13e36 android.hardware.neuralnetworks@1.3::IPreparedModel
0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback
5f1a4e0c29fc686ed476f9f04eed35e4405d21288cb2746b978d6891de5cc37d android.hardware.neuralnetworks@1.3::types
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
@@ -670,7 +672,7 @@
##
# BEGIN Radio HAL Merge Conflict Avoidance Buffer - STOPSHIP if present
##
-616456d7ce4435d88995f9fe0025a76bca14bd70799e4ca3ff4bae74d54d1166 android.hardware.radio@1.5::types
+430f8449ddb24c02284da561bfd24bb5a2a226d9ed2aec38e876e323e2b7eeee android.hardware.radio@1.5::types
c68f5bd87f747f8e7968ff66ecc548b2d26f8e186b7bb805c11d6c883a838fc6 android.hardware.radio@1.5::IRadio
e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication
9e962eff568dc8c712d83846f8c27460de5005ed9b836d3e08390e8aa56b5a46 android.hardware.radio@1.5::IRadioResponse
diff --git a/gnss/1.0/IGnssCallback.hal b/gnss/1.0/IGnssCallback.hal
index d62676f..311ab21 100644
--- a/gnss/1.0/IGnssCallback.hal
+++ b/gnss/1.0/IGnssCallback.hal
@@ -90,6 +90,7 @@
* - QZSS: 193-200
* - Galileo: 1-36
* - Beidou: 1-37
+ * - IRNSS: 1-14
*/
int16_t svid;
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index e2f2670..a23d72c 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -57,7 +57,15 @@
void TestRenderEngine::drawLayers() {
base::unique_fd bufferFence;
base::unique_fd readyFence;
- mRenderEngine->drawLayers(mDisplaySettings, mCompositionLayers,
+
+ std::vector<const renderengine::LayerSettings*> compositionLayerPointers;
+ compositionLayerPointers.reserve(mCompositionLayers.size());
+ std::transform(mCompositionLayers.begin(), mCompositionLayers.end(),
+ std::back_insert_iterator(compositionLayerPointers),
+ [](renderengine::LayerSettings& settings) -> renderengine::LayerSettings* {
+ return &settings;
+ });
+ mRenderEngine->drawLayers(mDisplaySettings, compositionLayerPointers,
mGraphicBuffer->getNativeBuffer(), true, std::move(bufferFence),
&readyFence);
int fd = readyFence.release();
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
index 7e0c33c..9e3cf0e 100644
--- a/graphics/composer/2.4/IComposerClient.hal
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -71,6 +71,51 @@
* setClientTargetProperty(ClientTargetProperty clientTargetProperty);
*/
SET_CLIENT_TARGET_PROPERTY = 0x105 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+
+ /**
+ * SET_LAYER_GENERIC_METADATA has this pseudo prototype
+ *
+ * setLayerGenericMetadata(string key, bool mandatory, vec<uint8_t> value);
+ *
+ * Sets a piece of generic metadata for the given layer. If this
+ * function is called twice with the same key but different values, the
+ * newer value must override the older one. Calling this function with a
+ * 0-length value must reset that key's metadata as if it had not been
+ * set.
+ *
+ * A given piece of metadata may either be mandatory or a hint
+ * (non-mandatory) as indicated by the second parameter. Mandatory
+ * metadata may affect the composition result, which is to say that it
+ * may cause a visible change in the final image. By contrast, hints may
+ * only affect the composition strategy, such as which layers are
+ * composited by the client, but must not cause a visible change in the
+ * final image. The value of the mandatory flag shall match the value
+ * returned from getLayerGenericMetadataKeys for the given key.
+ *
+ * Only keys which have been returned from getLayerGenericMetadataKeys()
+ * shall be accepted. Any other keys must result in an UNSUPPORTED error.
+ *
+ * The value passed into this function shall be the binary
+ * representation of a HIDL type corresponding to the given key. For
+ * example, a key of 'com.example.V1_3.Foo' shall be paired with a
+ * value of type com.example@1.3::Foo, which would be defined in a
+ * vendor HAL extension.
+ *
+ * This function will be encoded in the command buffer in this order:
+ * 1) The key length, stored as a uint32_t
+ * 2) The key itself, padded to a uint32_t boundary if necessary
+ * 3) The mandatory flag, stored as a uint32_t
+ * 4) The value length in bytes, stored as a uint32_t
+ * 5) The value itself, padded to a uint32_t boundary if necessary
+ *
+ * @param key indicates which metadata value should be set on this layer
+ * @param mandatory indicates whether this particular key represents
+ * mandatory metadata or a hint (non-mandatory metadata), as
+ * described above
+ * @param value is a binary representation of a HIDL struct
+ * corresponding to the key as described above
+ */
+ SET_LAYER_GENERIC_METADATA = 0x40e << @2.1::IComposerClient.Command:OPCODE_SHIFT,
};
/**
@@ -271,4 +316,33 @@
*/
setContentType(Display display, ContentType type)
generates (Error error);
+
+ struct LayerGenericMetadataKey {
+ /**
+ * Key names must comply with the requirements specified for
+ * getLayerGenericMetadataKeys below
+ */
+ string name;
+
+ /**
+ * The mandatory flag is defined in the description of
+ * setLayerGenericMetadata above
+ */
+ bool mandatory;
+ };
+
+ /**
+ * Retrieves the set of keys that may be passed into setLayerGenericMetadata
+ *
+ * Key names must meet the following requirements:
+ * - Must be specified in reverse domain name notation
+ * - Must not start with 'com.android' or 'android'
+ * - Must be unique within the returned vector
+ * - Must correspond to a matching HIDL struct type, which defines the
+ * structure of its values. For example, the key 'com.example.V1-3.Foo'
+ * should correspond to a value of type com.example@1.3::Foo, which is
+ * defined in a vendor HAL extension
+ */
+ getLayerGenericMetadataKeys()
+ generates(Error error, vec<LayerGenericMetadataKey> keys);
};
diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
index e84779e..eb35e5c 100644
--- a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
+++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
@@ -53,6 +53,27 @@
writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace));
endCommand();
}
+
+ void setLayerGenericMetadata(const hidl_string& key, const bool mandatory,
+ const hidl_vec<uint8_t>& value) {
+ const size_t commandSize = 3 + sizeToElements(key.size()) + sizeToElements(value.size());
+ if (commandSize > std::numeric_limits<uint16_t>::max()) {
+ LOG_FATAL("Too much generic metadata (%zu elements)", commandSize);
+ return;
+ }
+
+ beginCommand(IComposerClient::Command::SET_LAYER_GENERIC_METADATA,
+ static_cast<uint16_t>(commandSize));
+ write(key.size());
+ writeBlob(key.size(), reinterpret_cast<const unsigned char*>(key.c_str()));
+ write(mandatory);
+ write(value.size());
+ writeBlob(value.size(), value.data());
+ endCommand();
+ }
+
+ protected:
+ uint32_t sizeToElements(uint32_t size) { return (size + 3) / 4; }
};
// This class helps parse a command queue. Note that all sizes/lengths are in
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
index c864ce6..c889069 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -164,6 +164,14 @@
return mHal->setContentType(display, contentType);
}
+ Return<void> getLayerGenericMetadataKeys(
+ IComposerClient::getLayerGenericMetadataKeys_cb hidl_cb) override {
+ std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+ Error error = mHal->getLayerGenericMetadataKeys(&keys);
+ hidl_cb(error, keys);
+ return Void();
+ }
+
static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
auto client = std::make_unique<ComposerClientImpl>(hal);
return client->init() ? std::move(client) : nullptr;
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
index e0153ce..697d6b8 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerCommandEngine.h
@@ -74,6 +74,43 @@
CommandWriterBase* getWriter() { return static_cast<CommandWriterBase*>(mWriter.get()); }
+ bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
+ switch (static_cast<IComposerClient::Command>(command)) {
+ case IComposerClient::Command::SET_LAYER_GENERIC_METADATA:
+ return executeSetLayerGenericMetadata(length);
+ default:
+ return BaseType2_3::executeCommand(command, length);
+ }
+ }
+
+ bool executeSetLayerGenericMetadata(uint16_t length) {
+ // We expect at least two buffer lengths and a mandatory flag
+ if (length < 3) {
+ return false;
+ }
+
+ const uint32_t keySize = read();
+ std::string key;
+ key.resize(keySize);
+ readBlob(keySize, key.data());
+
+ const bool mandatory = read();
+
+ const uint32_t valueSize = read();
+ std::vector<uint8_t> value(valueSize);
+ readBlob(valueSize, value.data());
+
+ auto error = mHal->setLayerGenericMetadata(mCurrentDisplay, mCurrentLayer, key, mandatory,
+ value);
+ if (error != Error::NONE) {
+ // The error cast is safe because setLayerGenericMetadata doesn't
+ // return any of the new values added in V2_4::Error
+ mWriter->setError(getCommandLoc(), static_cast<V2_1::Error>(error));
+ }
+
+ return true;
+ }
+
ComposerHal* mHal;
};
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
index 277055c..58991c1 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -79,6 +79,10 @@
uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
std::vector<uint32_t>* outRequestMasks,
IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
+ virtual Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ bool mandatory, const std::vector<uint8_t>& value) = 0;
+ virtual Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
};
} // namespace hal
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
index 616852a..d28e006 100644
--- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -245,6 +245,61 @@
return err;
}
+ Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ bool mandatory, const std::vector<uint8_t>& value) override {
+ if (!mDispatch.setLayerGenericMetadata) {
+ return Error::UNSUPPORTED;
+ }
+
+ if (key.size() > std::numeric_limits<uint32_t>::max()) {
+ return Error::BAD_PARAMETER;
+ }
+
+ if (value.size() > std::numeric_limits<uint32_t>::max()) {
+ return Error::BAD_PARAMETER;
+ }
+
+ int32_t error = mDispatch.setLayerGenericMetadata(
+ mDevice, display, layer, static_cast<uint32_t>(key.size()), key.c_str(), mandatory,
+ static_cast<uint32_t>(value.size()), value.data());
+ return static_cast<Error>(error);
+ }
+
+ Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override {
+ if (!mDispatch.getLayerGenericMetadataKey) {
+ return Error::UNSUPPORTED;
+ }
+
+ std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+
+ uint32_t index = 0;
+ uint32_t keyLength = 0;
+ while (true) {
+ mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, nullptr, nullptr);
+ if (keyLength == 0) {
+ break;
+ }
+
+ IComposerClient::LayerGenericMetadataKey key;
+ std::string keyName;
+ keyName.resize(keyLength);
+ mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, keyName.data(),
+ &key.mandatory);
+ key.name = keyName;
+ keys.emplace_back(std::move(key));
+
+ // Only attempt to load the first 100 keys to avoid an infinite loop
+ // if something goes wrong
+ if (++index > 100) {
+ break;
+ }
+ }
+
+ *outKeys = std::move(keys);
+ return Error::NONE;
+ }
+
protected:
bool initDispatch() override {
if (!BaseType2_3::initDispatch()) {
@@ -267,6 +322,11 @@
this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType);
this->initOptionalDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_PROPERTY,
&mDispatch.getClientTargetProperty);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_GENERIC_METADATA,
+ &mDispatch.setLayerGenericMetadata);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_LAYER_GENERIC_METADATA_KEY,
+ &mDispatch.getLayerGenericMetadataKey);
+
return true;
}
@@ -319,6 +379,8 @@
HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes;
HWC2_PFN_SET_CONTENT_TYPE setContentType;
HWC2_PFN_GET_CLIENT_TARGET_PROPERTY getClientTargetProperty;
+ HWC2_PFN_SET_LAYER_GENERIC_METADATA setLayerGenericMetadata;
+ HWC2_PFN_GET_LAYER_GENERIC_METADATA_KEY getLayerGenericMetadataKey;
} mDispatch = {};
hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr;
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
index 8a9c006..8cdc452 100644
--- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -129,6 +129,16 @@
return mClient->setContentType(display, contentType);
}
+Error ComposerClient::getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) {
+ Error error = Error::NONE;
+ mClient->getLayerGenericMetadataKeys([&](const auto tmpError, const auto& tmpKeys) {
+ error = tmpError;
+ *outKeys = tmpKeys;
+ });
+ return error;
+}
+
} // namespace vts
} // namespace V2_4
} // namespace composer
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
index df75a48..3dd8e50 100644
--- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -93,6 +93,9 @@
Error setContentType(Display display, IComposerClient::ContentType contentType);
+ Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys);
+
private:
const sp<IComposerClient> mClient;
};
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index 800ff08..f6b46ff 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "graphics_composer_hidl_hal_test@2.4"
#include <algorithm>
+#include <regex>
#include <thread>
#include <android-base/logging.h>
@@ -625,6 +626,28 @@
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
android::hardware::PrintInstanceNameToString);
+TEST_F(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
+ std::vector<IComposerClient::LayerGenericMetadataKey> keys;
+ mComposerClient->getLayerGenericMetadataKeys(&keys);
+
+ std::regex reverseDomainName("^[a-zA-Z-]{2,}(\\.[a-zA-Z0-9-]+)+$");
+ std::unordered_set<std::string> uniqueNames;
+ for (const auto& key : keys) {
+ std::string name(key.name.c_str());
+
+ // Keys must not start with 'android' or 'com.android'
+ ASSERT_FALSE(name.find("android") == 0);
+ ASSERT_FALSE(name.find("com.android") == 0);
+
+ // Keys must be in reverse domain name format
+ ASSERT_TRUE(std::regex_match(name, reverseDomainName));
+
+ // Keys must be unique within this list
+ const auto& [iter, inserted] = uniqueNames.insert(name);
+ ASSERT_TRUE(inserted);
+ }
+}
+
} // namespace
} // namespace vts
} // namespace V2_4
diff --git a/health/utils/libhealthloop/utils.cpp b/health/utils/libhealthloop/utils.cpp
index b0d153f..ebfd8d8 100644
--- a/health/utils/libhealthloop/utils.cpp
+++ b/health/utils/libhealthloop/utils.cpp
@@ -40,6 +40,8 @@
.batteryChargeCounterPath = String8(String8::kEmptyString),
.batteryFullChargePath = String8(String8::kEmptyString),
.batteryCycleCountPath = String8(String8::kEmptyString),
+ .batteryCapacityLevelPath = String8(String8::kEmptyString),
+ .batteryChargeTimeToFullNowPath = String8(String8::kEmptyString),
.energyCounter = NULL,
.boot_min_cap = 0,
.screen_on = NULL,
diff --git a/light/aidl/Android.bp b/light/aidl/Android.bp
new file mode 100644
index 0000000..916a857
--- /dev/null
+++ b/light/aidl/Android.bp
@@ -0,0 +1,18 @@
+aidl_interface {
+ name: "android.hardware.light",
+ vendor_available: true,
+ srcs: [
+ "android/hardware/light/*.aidl",
+ ],
+ stability: "vintf",
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
+}
diff --git a/light/aidl/android/hardware/light/BrightnessMode.aidl b/light/aidl/android/hardware/light/BrightnessMode.aidl
new file mode 100644
index 0000000..bc29699
--- /dev/null
+++ b/light/aidl/android/hardware/light/BrightnessMode.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.light;
+
+@VintfStability
+enum BrightnessMode {
+ /**
+ * Light brightness is managed by a user setting.
+ */
+ USER = 0,
+
+ /**
+ * Light brightness is managed by a light sensor. This is typically used
+ * to control the display backlight, but not limited to it. HALs and
+ * hardware implementations are free to support sensor for other lights or
+ * none whatsoever.
+ */
+ SENSOR = 1,
+
+ /**
+ * Use a low-persistence mode for display backlights, where the pixel
+ * color transition times are lowered.
+ *
+ * When set, the device driver must switch to a mode optimized for low display
+ * persistence that is intended to be used when the device is being treated as a
+ * head mounted display (HMD). The actual display brightness in this mode is
+ * implementation dependent, and any value set for color in LightState may be
+ * overridden by the HAL implementation.
+ *
+ * For an optimal HMD viewing experience, the display must meet the following
+ * criteria in this mode:
+ * - Gray-to-Gray, White-to-Black, and Black-to-White switching time must be ≤ 3 ms.
+ * - The display must support low-persistence with ≤ 3.5 ms persistence.
+ * Persistence is defined as the amount of time for which a pixel is
+ * emitting light for a single frame.
+ * - Any "smart panel" or other frame buffering options that increase display
+ * latency are disabled.
+ * - Display brightness is set so that the display is still visible to the user
+ * under normal indoor lighting.
+ * - The display must update at 60 Hz at least, but higher refresh rates are
+ * recommended for low latency.
+ *
+ */
+ LOW_PERSISTENCE = 2,
+}
diff --git a/light/aidl/android/hardware/light/FlashMode.aidl b/light/aidl/android/hardware/light/FlashMode.aidl
new file mode 100644
index 0000000..00c6b6a
--- /dev/null
+++ b/light/aidl/android/hardware/light/FlashMode.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.light;
+
+@VintfStability
+enum FlashMode {
+ /**
+ * Keep the light steady on or off.
+ */
+ NONE = 0,
+ /**
+ * Flash the light at specified rate, potentially using a software-based
+ * implementation.
+ */
+ TIMED = 1,
+ /**
+ * Flash the light using hardware flashing support. This may or may not
+ * support a user-defined flashing rate or other features.
+ */
+ HARDWARE = 2,
+}
diff --git a/light/aidl/android/hardware/light/HwLight.aidl b/light/aidl/android/hardware/light/HwLight.aidl
new file mode 100644
index 0000000..43fdb4b
--- /dev/null
+++ b/light/aidl/android/hardware/light/HwLight.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 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.light;
+
+import android.hardware.light.LightType;
+
+/**
+ * A description of a single light. Multiple lights can map to the same physical
+ * LED. Separate physical LEDs are always represented by separate instances.
+ */
+@VintfStability
+parcelable HwLight {
+ /**
+ * Integer ID used for controlling this light
+ */
+ int id;
+
+ /**
+ * For a group of lights of the same logical type, sorting by ordinal should
+ * be give their physical order. No other meaning is carried by it.
+ */
+ int ordinal;
+
+ /**
+ * Logical type use of this light.
+ */
+ LightType type;
+}
diff --git a/light/aidl/android/hardware/light/HwLightState.aidl b/light/aidl/android/hardware/light/HwLightState.aidl
new file mode 100644
index 0000000..24d3250
--- /dev/null
+++ b/light/aidl/android/hardware/light/HwLightState.aidl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.light;
+
+import android.hardware.light.BrightnessMode;
+import android.hardware.light.FlashMode;
+
+/**
+ * The parameters that can be set for a given light.
+ *
+ * Not all lights must support all parameters. If you
+ * can do something backward-compatible, do it.
+ */
+@VintfStability
+parcelable HwLightState {
+ /**
+ * The color of the LED in ARGB.
+ *
+ * The implementation of this in the HAL and hardware is a best-effort one.
+ * - If a light can only do red or green and blue is requested, green
+ * should be shown.
+ * - If only a brightness ramp is supported, then this formula applies:
+ * unsigned char brightness = ((77*((color>>16)&0x00ff))
+ * + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
+ * - If only on and off are supported, 0 is off, anything else is on.
+ *
+ * The high byte should be ignored. Callers should set it to 0xff (which
+ * would correspond to 255 alpha).
+ */
+ int color;
+
+ /**
+ * To flash the light at a given rate, set flashMode to FLASH_TIMED.
+ */
+ FlashMode flashMode;
+
+ /**
+ * flashOnMs should be set to the number of milliseconds to turn the
+ * light on, before it's turned off.
+ */
+ int flashOnMs;
+
+ /**
+ * flashOfMs should be set to the number of milliseconds to turn the
+ * light off, before it's turned back on.
+ */
+ int flashOffMs;
+
+ BrightnessMode brightnessMode;
+}
diff --git a/light/aidl/android/hardware/light/ILights.aidl b/light/aidl/android/hardware/light/ILights.aidl
new file mode 100644
index 0000000..2253f73
--- /dev/null
+++ b/light/aidl/android/hardware/light/ILights.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.light;
+
+import android.hardware.light.HwLightState;
+import android.hardware.light.HwLight;
+
+/**
+ * Allows controlling logical lights/indicators, mapped to LEDs in a
+ * hardware-specific manner by the HAL implementation.
+ */
+@VintfStability
+interface ILights {
+ /**
+ * Set light identified by id to the provided state.
+ *
+ * If control over an invalid light is requested, this method exists with
+ * EX_UNSUPPORTED_OPERATION. Control over supported lights is done on a
+ * device-specific best-effort basis and unsupported sub-features will not
+ * be reported.
+ *
+ * @param id ID of logical light to set as returned by getLights()
+ * @param state describes what the light should look like.
+ */
+ void setLightState(in int id, in HwLightState state);
+
+ /**
+ * Discover what lights are supported by the HAL implementation.
+ *
+ * @return List of available lights
+ */
+ HwLight[] getLights();
+}
diff --git a/light/aidl/android/hardware/light/LightType.aidl b/light/aidl/android/hardware/light/LightType.aidl
new file mode 100644
index 0000000..9a7f656
--- /dev/null
+++ b/light/aidl/android/hardware/light/LightType.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.light;
+
+/**
+ * These light IDs correspond to logical lights, not physical.
+ * So for example, if your INDICATOR light is in line with your
+ * BUTTONS, it might make sense to also light the INDICATOR
+ * light to a reasonable color when the BUTTONS are lit.
+ */
+@VintfStability
+enum LightType {
+ BACKLIGHT = 0,
+ KEYBOARD = 1,
+ BUTTONS = 2,
+ BATTERY = 3,
+ NOTIFICATIONS = 4,
+ ATTENTION = 5,
+ BLUETOOTH = 6,
+ WIFI = 7,
+ MICROPHONE = 8,
+}
diff --git a/light/aidl/default/Android.bp b/light/aidl/default/Android.bp
new file mode 100644
index 0000000..ae3f463
--- /dev/null
+++ b/light/aidl/default/Android.bp
@@ -0,0 +1,16 @@
+cc_binary {
+ name: "android.hardware.lights-service.example",
+ relative_install_path: "hw",
+ init_rc: ["lights-default.rc"],
+ vintf_fragments: ["lights-default.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.light-ndk_platform",
+ ],
+ srcs: [
+ "Lights.cpp",
+ "main.cpp",
+ ],
+}
diff --git a/light/aidl/default/Lights.cpp b/light/aidl/default/Lights.cpp
new file mode 100644
index 0000000..74747d5
--- /dev/null
+++ b/light/aidl/default/Lights.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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 "Lights.h"
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace light {
+
+ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) {
+ LOG(INFO) << "Lights setting state for id=" << id << " to color " << std::hex << state.color;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* /*lights*/) {
+ LOG(INFO) << "Lights reporting supported lights";
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace light
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/light/aidl/default/Lights.h b/light/aidl/default/Lights.h
new file mode 100644
index 0000000..8cba5a1
--- /dev/null
+++ b/light/aidl/default/Lights.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/light/BnLights.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace light {
+
+// Default implementation that reports no supported lights.
+class Lights : public BnLights {
+ ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override;
+ ndk::ScopedAStatus getLights(std::vector<HwLight>* types) override;
+};
+
+} // namespace light
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/light/aidl/default/lights-default.rc b/light/aidl/default/lights-default.rc
new file mode 100644
index 0000000..687ec97
--- /dev/null
+++ b/light/aidl/default/lights-default.rc
@@ -0,0 +1,5 @@
+service vendor.light-default /vendor/bin/hw/android.hardware.lights-service.example
+ class hal
+ user nobody
+ group nobody
+ shutdown critical
diff --git a/light/aidl/default/lights-default.xml b/light/aidl/default/lights-default.xml
new file mode 100644
index 0000000..db604d6
--- /dev/null
+++ b/light/aidl/default/lights-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.light</name>
+ <fqname>ILights/default</fqname>
+ </hal>
+</manifest>
diff --git a/light/aidl/default/main.cpp b/light/aidl/default/main.cpp
new file mode 100644
index 0000000..a860bf4
--- /dev/null
+++ b/light/aidl/default/main.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Lights.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using ::aidl::android::hardware::light::Lights;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<Lights> lights = ndk::SharedRefBase::make<Lights>();
+
+ const std::string instance = std::string() + Lights::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reached
+}
diff --git a/light/aidl/vts/functional/Android.bp b/light/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..3dd8cf6
--- /dev/null
+++ b/light/aidl/vts/functional/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalLightTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsHalLightTargetTest.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ ],
+ static_libs: [
+ "android.hardware.light-cpp",
+ ],
+ test_suites: [
+ "vts-core",
+ ],
+}
diff --git a/light/aidl/vts/functional/VtsHalLightTargetTest.cpp b/light/aidl/vts/functional/VtsHalLightTargetTest.cpp
new file mode 100644
index 0000000..3c26278
--- /dev/null
+++ b/light/aidl/vts/functional/VtsHalLightTargetTest.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "light_aidl_hal_test"
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android-base/logging.h>
+#include <android/hardware/light/ILights.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include <unistd.h>
+#include <set>
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::light::BrightnessMode;
+using android::hardware::light::FlashMode;
+using android::hardware::light::HwLight;
+using android::hardware::light::HwLightState;
+using android::hardware::light::ILights;
+using android::hardware::light::LightType;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+const std::set<LightType> kAllTypes{android::enum_range<LightType>().begin(),
+ android::enum_range<LightType>().end()};
+
+class LightsAidl : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ lights = android::waitForDeclaredService<ILights>(String16(GetParam().c_str()));
+ ASSERT_NE(lights, nullptr);
+ ASSERT_TRUE(lights->getLights(&supportedLights).isOk());
+ }
+
+ sp<ILights> lights;
+ std::vector<HwLight> supportedLights;
+
+ virtual void TearDown() override {
+ for (const HwLight& light : supportedLights) {
+ HwLightState off;
+ off.color = 0x00000000;
+ off.flashMode = FlashMode::NONE;
+ off.brightnessMode = BrightnessMode::USER;
+ EXPECT_TRUE(lights->setLightState(light.id, off).isOk());
+ }
+
+ // must leave the device in a useable condition
+ for (const HwLight& light : supportedLights) {
+ if (light.type == LightType::BACKLIGHT) {
+ HwLightState backlightOn;
+ backlightOn.color = 0xFFFFFFFF;
+ backlightOn.flashMode = FlashMode::TIMED;
+ backlightOn.brightnessMode = BrightnessMode::USER;
+ EXPECT_TRUE(lights->setLightState(light.id, backlightOn).isOk());
+ }
+ }
+ }
+};
+
+/**
+ * Ensure all reported lights actually work.
+ */
+TEST_P(LightsAidl, TestSupported) {
+ HwLightState whiteFlashing;
+ whiteFlashing.color = 0xFFFFFFFF;
+ whiteFlashing.flashMode = FlashMode::TIMED;
+ whiteFlashing.flashOnMs = 100;
+ whiteFlashing.flashOffMs = 50;
+ whiteFlashing.brightnessMode = BrightnessMode::USER;
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(lights->setLightState(light.id, whiteFlashing).isOk());
+ }
+}
+
+/**
+ * Ensure all reported lights have one of the supported types.
+ */
+TEST_P(LightsAidl, TestSupportedLightTypes) {
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(kAllTypes.find(light.type) != kAllTypes.end());
+ }
+}
+
+/**
+ * Ensure all lights have a unique id.
+ */
+TEST_P(LightsAidl, TestUniqueIds) {
+ std::set<int> ids;
+ for (const HwLight& light : supportedLights) {
+ EXPECT_TRUE(ids.find(light.id) == ids.end());
+ ids.insert(light.id);
+ }
+}
+
+/**
+ * Ensure all lights have a unique ordinal for a given type.
+ */
+TEST_P(LightsAidl, TestUniqueOrdinalsForType) {
+ std::map<int, std::set<int>> ordinalsByType;
+ for (const HwLight& light : supportedLights) {
+ auto& ordinals = ordinalsByType[(int)light.type];
+ EXPECT_TRUE(ordinals.find(light.ordinal) == ordinals.end());
+ ordinals.insert(light.ordinal);
+ }
+}
+
+/**
+ * Ensure EX_UNSUPPORTED_OPERATION is returned if LOW_PERSISTENCE is not supported.
+ */
+TEST_P(LightsAidl, TestLowPersistence) {
+ HwLightState lowPersistence;
+ lowPersistence.color = 0xFF123456;
+ lowPersistence.flashMode = FlashMode::TIMED;
+ lowPersistence.flashOnMs = 100;
+ lowPersistence.flashOffMs = 50;
+ lowPersistence.brightnessMode = BrightnessMode::LOW_PERSISTENCE;
+ for (const HwLight& light : supportedLights) {
+ Status status = lights->setLightState(light.id, lowPersistence);
+ EXPECT_TRUE(status.isOk() || Status::EX_UNSUPPORTED_OPERATION == status.exceptionCode());
+ }
+}
+
+/**
+ * Ensure EX_UNSUPPORTED_OPERATION is returns for an invalid light id.
+ */
+TEST_P(LightsAidl, TestInvalidLightIdUnsupported) {
+ int maxId = INT_MIN;
+ for (const HwLight& light : supportedLights) {
+ maxId = std::max(maxId, light.id);
+ }
+
+ Status status = lights->setLightState(maxId + 1, HwLightState());
+ EXPECT_TRUE(status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION);
+}
+
+INSTANTIATE_TEST_SUITE_P(Lights, LightsAidl,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ILights::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/light/utils/Android.bp b/light/utils/Android.bp
index 4c287e4..e901129 100644
--- a/light/utils/Android.bp
+++ b/light/utils/Android.bp
@@ -23,7 +23,11 @@
shared_libs: [
"android.hardware.light@2.0",
"libbase",
+ "libbinder",
"libhidlbase",
"libutils",
],
+ static_libs: [
+ "android.hardware.light-cpp",
+ ],
}
diff --git a/light/utils/main.cpp b/light/utils/main.cpp
index b834132..b9b6489 100644
--- a/light/utils/main.cpp
+++ b/light/utils/main.cpp
@@ -19,34 +19,23 @@
#include <android-base/logging.h>
#include <android/hardware/light/2.0/ILight.h>
+#include <android/hardware/light/ILights.h>
+#include <binder/IServiceManager.h>
+
+using android::sp;
+using android::waitForVintfService;
+using android::binder::Status;
+using android::hardware::hidl_vec;
+
+namespace V2_0 = android::hardware::light::V2_0;
+namespace aidl = android::hardware::light;
void error(const std::string& msg) {
LOG(ERROR) << msg;
std::cerr << msg << std::endl;
}
-int main(int argc, char* argv[]) {
- using ::android::hardware::hidl_vec;
- using ::android::hardware::light::V2_0::Brightness;
- using ::android::hardware::light::V2_0::Flash;
- using ::android::hardware::light::V2_0::ILight;
- using ::android::hardware::light::V2_0::LightState;
- using ::android::hardware::light::V2_0::Status;
- using ::android::hardware::light::V2_0::Type;
- using ::android::sp;
-
- sp<ILight> service = ILight::getService();
- if (service == nullptr) {
- error("Could not retrieve light service.");
- return -1;
- }
-
- static LightState off = {
- .color = 0u,
- .flashMode = Flash::NONE,
- .brightnessMode = Brightness::USER,
- };
-
+int parseArgs(int argc, char* argv[], unsigned int* color) {
if (argc > 2) {
error("Usage: blank_screen [color]");
return -1;
@@ -54,25 +43,78 @@
if (argc > 1) {
char* col_ptr;
- unsigned int col_new;
- col_new = strtoul(argv[1], &col_ptr, 0);
+ *color = strtoul(argv[1], &col_ptr, 0);
if (*col_ptr != '\0') {
error("Failed to convert " + std::string(argv[1]) + " to number");
return -1;
}
- off.color = col_new;
+
+ return 0;
}
- service->getSupportedTypes([&](const hidl_vec<Type>& types) {
- for (Type type : types) {
- Status ret = service->setLight(type, off);
- if (ret != Status::SUCCESS) {
- error("Failed to shut off screen for type " +
+ *color = 0u;
+ return 0;
+}
+
+void setToColorAidl(sp<aidl::ILights> hal, unsigned int color) {
+ static aidl::HwLightState off;
+ off.color = color;
+ off.flashMode = aidl::FlashMode::NONE;
+ off.brightnessMode = aidl::BrightnessMode::USER;
+
+ std::vector<aidl::HwLight> lights;
+ Status status = hal->getLights(&lights);
+ if (!status.isOk()) {
+ error("Failed to list lights");
+ return;
+ }
+
+ for (auto light : lights) {
+ Status setStatus = hal->setLightState(light.id, off);
+ if (!setStatus.isOk()) {
+ error("Failed to shut off light id " + std::to_string(light.id));
+ }
+ }
+}
+
+void setToColorHidl(sp<V2_0::ILight> hal, unsigned int color) {
+ static V2_0::LightState off = {
+ .color = color,
+ .flashMode = V2_0::Flash::NONE,
+ .brightnessMode = V2_0::Brightness::USER,
+ };
+
+ hal->getSupportedTypes([&](const hidl_vec<V2_0::Type>& types) {
+ for (auto type : types) {
+ V2_0::Status ret = hal->setLight(type, off);
+ if (ret != V2_0::Status::SUCCESS) {
+ error("Failed to shut off light for type " +
std::to_string(static_cast<int>(type)));
}
}
});
+}
- return 0;
+int main(int argc, char* argv[]) {
+ unsigned int inputColor;
+ int result = parseArgs(argc, argv, &inputColor);
+ if (result != 0) {
+ return result;
+ }
+
+ auto aidlHal = waitForVintfService<aidl::ILights>();
+ if (aidlHal != nullptr) {
+ setToColorAidl(aidlHal, inputColor);
+ return 0;
+ }
+
+ sp<V2_0::ILight> hidlHal = V2_0::ILight::getService();
+ if (hidlHal != nullptr) {
+ setToColorHidl(hidlHal, inputColor);
+ return 0;
+ }
+
+ error("Could not retrieve light service.");
+ return -1;
}
diff --git a/neuralnetworks/1.3/Android.bp b/neuralnetworks/1.3/Android.bp
index 56011e2..7b02cc5 100644
--- a/neuralnetworks/1.3/Android.bp
+++ b/neuralnetworks/1.3/Android.bp
@@ -11,6 +11,7 @@
"IBuffer.hal",
"IDevice.hal",
"IExecutionCallback.hal",
+ "IFencedExecutionCallback.hal",
"IPreparedModel.hal",
"IPreparedModelCallback.hal",
],
diff --git a/neuralnetworks/1.3/IFencedExecutionCallback.hal b/neuralnetworks/1.3/IFencedExecutionCallback.hal
new file mode 100644
index 0000000..39076b9
--- /dev/null
+++ b/neuralnetworks/1.3/IFencedExecutionCallback.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.neuralnetworks@1.3;
+
+import @1.2::Timing;
+import ErrorStatus;
+
+/**
+ * IFencedExecutionCallback can be used to query the error status result
+ * and duration information from an IPreparedModel::executeFenced call.
+ */
+interface IFencedExecutionCallback {
+
+ /**
+ * The getExecutionInfo method is used by the clients to query error status
+ * result and duration information. The method must only be called after the actual
+ * evaluation has finished or resulted in an runtime error, as indicated by the status
+ * of the sync fence returned by the IPreparedModel::executeFenced call, otherwise
+ * GENERAL_FAILURE must be returned.
+ *
+ * @return status Error status returned from the asynchronously dispatched execution
+ * must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the asynchronous task resulted in an
+ * unspecified error
+ * @return timing Duration of execution. Unless MeasureTiming::YES was passed when
+ * launching the execution and status is NONE, all times must
+ * be reported as UINT64_MAX. A driver may choose to report
+ * any time as UINT64_MAX, indicating that particular measurement is
+ * not available.
+ */
+ getExecutionInfo() generates (ErrorStatus status, Timing timing);
+};
diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal
index bce6ee2..f84bcf4 100644
--- a/neuralnetworks/1.3/IPreparedModel.hal
+++ b/neuralnetworks/1.3/IPreparedModel.hal
@@ -24,6 +24,7 @@
import OptionalTimePoint;
import Request;
import IExecutionCallback;
+import IFencedExecutionCallback;
/**
* IPreparedModel describes a model that has been prepared for execution and
@@ -91,7 +92,8 @@
* execution cannot be finished by the deadline, the
* execution must be aborted.
* @param callback A callback object used to return the error status of
- * the execution. The callback object's notify function must
+ * the execution, shape information of model output operands, and
+ * duration of execution. The callback object's notify function must
* be called exactly once, even if the execution was
* unsuccessful.
* @return status Error status of the call, must be:
@@ -187,4 +189,57 @@
OptionalTimePoint deadline)
generates (ErrorStatus status, vec<OutputShape> outputShapes,
Timing timing);
+
+ /**
+ * Launch a fenced asynchronous execution on a prepared model.
+ *
+ * The execution is performed asynchronously with respect to the caller.
+ * executeFenced must fully validate the request, and only accept one that is
+ * guaranteed to be completed, unless a hardware failure or kernel panic happens on the device.
+ * If there is an error during validation, executeFenced must immediately return with
+ * the corresponding ErrorStatus. If the request is valid and there is no error launching,
+ * executeFenced must dispatch an asynchronous task to perform the execution in the
+ * background, and immediately return with ErrorStatus::NONE, a sync_fence that will be
+ * signaled once the execution is completed, and a callback that can be used by the client
+ * to query the duration and runtime error status. If the task has finished
+ * before the call returns, empty handle may be returned for the sync fence. If the
+ * asynchronous task fails to launch, executeFenced must immediately return with
+ * ErrorStatus::GENERAL_FAILURE, and empty handle for the sync fence and nullptr
+ * for callback. The execution must wait for all the sync fences (if any) in wait_for to be
+ * signaled before starting the actual execution.
+ *
+ * If any of sync fences in wait_for changes to error status after the executeFenced
+ * call succeeds, the driver must immediately set the returned sync fence to error status.
+ *
+ * When the asynchronous task has finished its execution, it must
+ * immediately signal the sync_fence created when dispatching. After
+ * the sync_fence is signaled, the task must not modify the content of
+ * any data object referenced by 'request' (described by the
+ * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}).
+ *
+ * Any number of calls to the executeFenced, execute* and executeSynchronously*
+ * functions, in any combination, may be made concurrently, even on the same
+ * IPreparedModel object.
+ *
+ * @param request The input and output information on which the prepared
+ * model is to be executed.
+ * @param waitFor A vector of sync fence file descriptors.
+ * Execution must not start until all sync fences have been signaled.
+ * @param measure Specifies whether or not to measure duration of the execution.
+ * The duration runs from the time the driver sees the call
+ * to the executeFenced function to the time sync_fence is triggered.
+ * @return status Error status of the call, must be:
+ * - NONE if task is successfully launched
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if one of the input arguments is invalid, including
+ * fences in error states.
+ * @return syncFence The sync fence that will be triggered when the task is completed.
+ * The sync fence will be set to error if a critical error,
+ * e.g. hardware failure or kernel panic, occurs when doing execution.
+ * @return callback The IFencedExecutionCallback can be used to query information like duration
+ * and error status when the execution is completed.
+ */
+ executeFenced(Request request, vec<handle> waitFor, MeasureTiming measure)
+ generates (ErrorStatus status, handle syncFence, IFencedExecutionCallback callback);
};
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index ce2d3a9..8e7e9b9 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -65,6 +65,7 @@
"libhidlmemory",
"libneuralnetworks_generated_test_harness",
"libneuralnetworks_utils",
+ "libsync",
],
whole_static_libs: [
"neuralnetworks_generated_V1_0_example",
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index cba1f77..b811149 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -29,11 +29,13 @@
#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
#include <android/hardware/neuralnetworks/1.2/types.h>
#include <android/hardware/neuralnetworks/1.3/IDevice.h>
+#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
#include <android/hardware/neuralnetworks/1.3/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
+#include <android/sync.h>
#include <gtest/gtest.h>
#include <hidlmemory/mapping.h>
@@ -70,7 +72,7 @@
namespace {
-enum class Executor { ASYNC, SYNC, BURST };
+enum class Executor { ASYNC, SYNC, BURST, FENCED };
enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
@@ -562,6 +564,43 @@
break;
}
+ case Executor::FENCED: {
+ SCOPED_TRACE("fenced");
+ ErrorStatus result;
+ hidl_handle sync_fence_handle;
+ sp<IFencedExecutionCallback> fenced_callback;
+ Return<void> ret = preparedModel->executeFenced(
+ request, {}, testConfig.measureTiming,
+ [&result, &sync_fence_handle, &fenced_callback](
+ ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ result = error;
+ sync_fence_handle = handle;
+ fenced_callback = callback;
+ });
+ ASSERT_TRUE(ret.isOk());
+ if (result != ErrorStatus::NONE) {
+ ASSERT_EQ(sync_fence_handle.getNativeHandle(), nullptr);
+ ASSERT_EQ(fenced_callback, nullptr);
+ executionStatus = ErrorStatus::GENERAL_FAILURE;
+ } else if (sync_fence_handle.getNativeHandle()) {
+ constexpr int kInfiniteTimeout = -1;
+ int sync_fd = sync_fence_handle.getNativeHandle()->data[0];
+ ASSERT_GT(sync_fd, 0);
+ int r = sync_wait(sync_fd, kInfiniteTimeout);
+ ASSERT_GE(r, 0);
+ }
+ if (result == ErrorStatus::NONE) {
+ ASSERT_NE(fenced_callback, nullptr);
+ Return<void> ret = fenced_callback->getExecutionInfo(
+ [&executionStatus, &timing](ErrorStatus error, Timing t) {
+ executionStatus = error;
+ timing = t;
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+ break;
+ }
}
if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
@@ -635,7 +674,7 @@
case TestKind::GENERAL: {
outputTypesList = {OutputType::FULLY_SPECIFIED};
measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
- executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+ executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST, Executor::FENCED};
} break;
case TestKind::DYNAMIC_SHAPE: {
outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
@@ -671,7 +710,8 @@
const TestModel& coupledModel) {
const std::vector<OutputType> outputTypesList = {OutputType::FULLY_SPECIFIED};
const std::vector<MeasureTiming> measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
- const std::vector<Executor> executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+ const std::vector<Executor> executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST,
+ Executor::FENCED};
for (const OutputType outputType : outputTypesList) {
for (const MeasureTiming measureTiming : measureTimingList) {
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index be4112a..1ddd09c 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -16,7 +16,9 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
+#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
#include <chrono>
+
#include "1.0/Utils.h"
#include "1.3/Callbacks.h"
#include "ExecutionBurstController.h"
@@ -136,6 +138,22 @@
burst->freeMemory(keys.front());
}
}
+
+ // dispatch
+ {
+ SCOPED_TRACE(message + " [executeFenced]");
+ Return<void> ret = preparedModel->executeFenced(
+ request, {}, MeasureTiming::NO,
+ [](ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ if (error != ErrorStatus::DEVICE_UNAVAILABLE) {
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+ }
+ ASSERT_EQ(handle.getNativeHandle(), nullptr);
+ ASSERT_EQ(callback, nullptr);
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
}
///////////////////////// REMOVE INPUT ////////////////////////////////////
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
index 93c8f13..28cc8ff 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -133,6 +133,35 @@
// Forward declaration from ValidateBurst.cpp
void validateBurst(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
+// Validate sync_fence handles for dispatch with valid input
+void validateExecuteFenced(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ SCOPED_TRACE("Expecting request to fail [executeFenced]");
+ Return<void> ret_null =
+ preparedModel->executeFenced(request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO,
+ [](ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+ ASSERT_EQ(handle.getNativeHandle(), nullptr);
+ ASSERT_EQ(callback, nullptr);
+ });
+ ASSERT_TRUE(ret_null.isOk());
+
+ native_handle_t* nativeHandle = native_handle_create(1, 0);
+ ASSERT_NE(nullptr, nativeHandle);
+ nativeHandle->data[0] = -1;
+ hidl_handle hidlHandle;
+ hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true);
+ Return<void> ret_invalid =
+ preparedModel->executeFenced(request, {hidlHandle}, V1_2::MeasureTiming::NO,
+ [](ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+ ASSERT_EQ(handle.getNativeHandle(), nullptr);
+ ASSERT_EQ(callback, nullptr);
+ });
+ ASSERT_TRUE(ret_invalid.isOk());
+}
+
void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request,
std::pair<bool, bool> supportsDeadlines) {
const auto [prepareModelDeadlineSupported, executionDeadlineSupported] = supportsDeadlines;
@@ -144,6 +173,7 @@
if (preparedModel == nullptr) return;
validateRequest(preparedModel, request, executionDeadlineSupported);
+ validateExecuteFenced(preparedModel, request);
// TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2.
ASSERT_TRUE(nn::compliantWithV1_0(request));
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 5482aca..c0fa8af 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -600,6 +600,9 @@
/** Information about any closed subscriber group ID for this cell */
OptionalCsgInfo optionalCsgInfo;
+
+ /** Bands used by the cell. */
+ vec<EutranBands> bands;
};
/**
@@ -615,8 +618,8 @@
/** Additional PLMN-IDs beyond the primary PLMN broadcast for this cell */
vec<string> additionalPlmns;
- /** Band used by the cell */
- NgranBands band;
+ /** Bands used by the cell. */
+ vec<NgranBands> bands;
};
struct CellInfoGsm {
diff --git a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
index f69cf87..cd8cc3e 100644
--- a/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
+++ b/rebootescrow/aidl/vts/functional/VtsHalRebootEscrowTargetTest.cpp
@@ -26,6 +26,9 @@
using android::String16;
using android::hardware::rebootescrow::IRebootEscrow;
+#define SKIP_UNSUPPORTED \
+ if (rebootescrow == nullptr) GTEST_SKIP() << "Not supported on this device"
+
/**
* This tests that the key can be written, read, and removed. It does not test
* that the key survives a reboot. That needs a host-based test.
@@ -36,7 +39,6 @@
public:
virtual void SetUp() override {
rebootescrow = android::waitForDeclaredService<IRebootEscrow>(String16(GetParam().c_str()));
- ASSERT_NE(rebootescrow, nullptr);
}
sp<IRebootEscrow> rebootescrow;
@@ -59,6 +61,8 @@
};
TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_Success) {
+ SKIP_UNSUPPORTED;
+
ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
std::vector<uint8_t> actualKey;
@@ -67,6 +71,8 @@
}
TEST_P(RebootEscrowAidlTest, StoreAndRetrieve_SecondRetrieveSucceeds) {
+ SKIP_UNSUPPORTED;
+
ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
std::vector<uint8_t> actualKey;
@@ -78,6 +84,8 @@
}
TEST_P(RebootEscrowAidlTest, StoreTwiceOverwrites_Success) {
+ SKIP_UNSUPPORTED;
+
ASSERT_TRUE(rebootescrow->storeKey(KEY_1).isOk());
ASSERT_TRUE(rebootescrow->storeKey(KEY_2).isOk());
@@ -87,6 +95,8 @@
}
TEST_P(RebootEscrowAidlTest, StoreEmpty_AfterGetEmptyKey_Success) {
+ SKIP_UNSUPPORTED;
+
rebootescrow->storeKey(KEY_1);
rebootescrow->storeKey(EMPTY_KEY);
diff --git a/tv/tuner/1.0/TEST_MAPPING b/tv/tuner/1.0/TEST_MAPPING
new file mode 100644
index 0000000..1979887
--- /dev/null
+++ b/tv/tuner/1.0/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "VtsHalTvTunerV1_0TargetTest"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp
index 7d6b990..3637708 100644
--- a/tv/tuner/1.0/vts/functional/Android.bp
+++ b/tv/tuner/1.0/vts/functional/Android.bp
@@ -30,5 +30,10 @@
shared_libs: [
"libbinder",
],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+
+ require_root: true,
}
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 4e7dcc3..820c58c 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -31,8 +31,11 @@
#include <android/hardware/tv/tuner/1.0/types.h>
#include <binder/MemoryDealer.h>
#include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
#include <hidl/Status.h>
#include <hidlmemory/FrameworkUtils.h>
#include <utils/Condition.h>
@@ -633,23 +636,10 @@
android::Mutex::Autolock autoLock(mRecordThreadLock);
}
-// Test environment for Tuner HIDL HAL.
-class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static TunerHidlEnvironment* Instance() {
- static TunerHidlEnvironment* instance = new TunerHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<ITuner>(); }
-};
-
-class TunerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class TunerHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- mService = ::testing::VtsHalHidlTargetTestBase::getService<ITuner>(
- TunerHidlEnvironment::Instance()->getServiceName<ITuner>());
+ mService = ITuner::getService(GetParam());
ASSERT_NE(mService, nullptr);
}
@@ -1242,7 +1232,7 @@
/*
* API STATUS TESTS
*/
-TEST_F(TunerHidlTest, CreateFrontend) {
+TEST_P(TunerHidlTest, CreateFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -1262,7 +1252,7 @@
}
}
-TEST_F(TunerHidlTest, TuneFrontend) {
+TEST_P(TunerHidlTest, TuneFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -1282,7 +1272,7 @@
}
}
-TEST_F(TunerHidlTest, StopTuneFrontend) {
+TEST_P(TunerHidlTest, StopTuneFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -1302,7 +1292,7 @@
}
}
-TEST_F(TunerHidlTest, CloseFrontend) {
+TEST_P(TunerHidlTest, CloseFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -1322,7 +1312,7 @@
}
}
-TEST_F(TunerHidlTest, CreateDemuxWithFrontend) {
+TEST_P(TunerHidlTest, CreateDemuxWithFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -1349,22 +1339,22 @@
}
}
-TEST_F(TunerHidlTest, CreateDemux) {
+TEST_P(TunerHidlTest, CreateDemux) {
description("Create Demux");
ASSERT_TRUE(createDemux());
}
-TEST_F(TunerHidlTest, CloseDemux) {
+TEST_P(TunerHidlTest, CloseDemux) {
description("Close Demux");
ASSERT_TRUE(closeDemux());
}
-TEST_F(TunerHidlTest, CreateDescrambler) {
+TEST_P(TunerHidlTest, CreateDescrambler) {
description("Create Descrambler");
ASSERT_TRUE(createDescrambler());
}
-TEST_F(TunerHidlTest, CloseDescrambler) {
+TEST_P(TunerHidlTest, CloseDescrambler) {
description("Close Descrambler");
ASSERT_TRUE(closeDescrambler());
}
@@ -1374,7 +1364,7 @@
*
* TODO: re-enable the tests after finalizing the testing stream.
*/
-/*TEST_F(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) {
+/*TEST_P(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) {
description("Feed ts data from playback and configure pes filter to get output");
// todo modulize the filter conf parser
@@ -1417,7 +1407,7 @@
ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles));
}
-TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) {
+TEST_P(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) {
description("Feed ts data from frontend and test with PES filter");
// todo modulize the filter conf parser
@@ -1447,7 +1437,7 @@
ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles));
}
-TEST_F(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
+TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
description("Feed ts data from frontend to recording and test with ts record filter");
// todo modulize the filter conf parser
@@ -1487,11 +1477,7 @@
} // namespace
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(TunerHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- TunerHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, TunerHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
index b9a80ec..0fdfa5d 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -49,4 +49,9 @@
* A haptic effect that simulates quick downwards movement with gravity.
*/
QUICK_FALL,
+ /**
+ * This very short effect should produce a light crisp sensation intended
+ * to be used repetitively for dynamic feedback.
+ */
+ LIGHT_TICK,
}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index f553664..06a8bf5 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -158,12 +158,31 @@
int getCompositionSizeMax();
/**
+ * List of supported effect primitive.
+ *
+ * Return the effect primitives which are supported by the compose API.
+ * Implementations are expected to support all primitives of the interface
+ * version that they implement.
+ */
+ CompositePrimitive[] getSupportedPrimitives();
+
+ /**
+ * Retrieve effect primitive's duration in milliseconds.
+ *
+ * Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
+ *
+ * @return Best effort estimation of effect primitive's duration.
+ * @param primitive Effect primitive being queried.
+ */
+ int getPrimitiveDuration(CompositePrimitive primitive);
+
+ /**
* Fire off a string of effect primitives, combined to perform richer effects.
*
* Support is reflected in getCapabilities (CAP_COMPOSE_EFFECTS).
*
* Doing this operation while the vibrator is already on is undefined behavior. Clients should
- * explicitly call off.
+ * explicitly call off. IVibratorCallback.onComplete() support is required for this API.
*
* @param composite Array of composition parameters.
*/
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index cedd9cb..0d7131a 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -113,6 +113,26 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported) {
+ *supported = {
+ CompositePrimitive::NOOP, CompositePrimitive::CLICK,
+ CompositePrimitive::THUD, CompositePrimitive::SPIN,
+ CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
+ CompositePrimitive::QUICK_FALL, CompositePrimitive::LIGHT_TICK,
+ };
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive,
+ int32_t* durationMs) {
+ if (primitive != CompositePrimitive::NOOP) {
+ *durationMs = 100;
+ } else {
+ *durationMs = 0;
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite,
const std::shared_ptr<IVibratorCallback>& callback) {
if (composite.size() > kComposeSizeMax) {
@@ -127,7 +147,7 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (e.primitive < CompositePrimitive::NOOP ||
- e.primitive > CompositePrimitive::QUICK_FALL) {
+ e.primitive > CompositePrimitive::LIGHT_TICK) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
}
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index 0eb957d..c3f3616 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -36,6 +36,9 @@
ndk::ScopedAStatus setExternalControl(bool enabled) override;
ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs);
ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize);
+ ndk::ScopedAStatus getSupportedPrimitives(std::vector<CompositePrimitive>* supported) override;
+ ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive,
+ int32_t* durationMs) override;
ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
const std::shared_ptr<IVibratorCallback>& callback) override;
ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override;
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index f197763..411fe7a 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -261,6 +261,29 @@
}
}
+TEST_P(VibratorAidl, GetSupportedPrimitives) {
+ if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ std::vector<CompositePrimitive> supported;
+
+ EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());
+
+ std::sort(supported.begin(), supported.end());
+
+ EXPECT_EQ(kCompositePrimitives, supported);
+ }
+}
+
+TEST_P(VibratorAidl, GetPrimitiveDuration) {
+ if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ int32_t duration;
+
+ for (auto primitive : kCompositePrimitives) {
+ EXPECT_EQ(Status::EX_NONE,
+ vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode());
+ }
+ }
+}
+
TEST_P(VibratorAidl, ComposeValidPrimitives) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
int32_t maxDelay, maxSize;
@@ -357,6 +380,30 @@
}
}
+TEST_P(VibratorAidl, ComposeCallback) {
+ if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ std::promise<void> completionPromise;
+ std::future<void> completionFuture{completionPromise.get_future()};
+ sp<CompletionCallback> callback =
+ new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+ CompositePrimitive primitive = CompositePrimitive::CLICK;
+ CompositeEffect effect;
+ std::vector<CompositeEffect> composite;
+ int32_t duration;
+
+ effect.delayMs = 0;
+ effect.primitive = primitive;
+ effect.scale = 1.0f;
+ composite.emplace_back(effect);
+
+ EXPECT_EQ(Status::EX_NONE,
+ vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode());
+ EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode());
+ EXPECT_EQ(completionFuture.wait_for(std::chrono::milliseconds(duration * 2)),
+ std::future_status::ready);
+ }
+}
+
TEST_P(VibratorAidl, AlwaysOn) {
if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) {
std::vector<Effect> supported;