Merge "Added new owner to broadcast AIDL HAL"
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 11a083c..d59def7 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -627,6 +627,14 @@
         </interface>
     </hal>
     <hal format="aidl" optional="true">
+        <name>android.hardware.tv.input</name>
+        <version>1</version>
+        <interface>
+            <name>ITvInput</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="aidl" optional="true">
         <name>android.hardware.usb</name>
         <interface>
             <name>IUsb</name>
diff --git a/light/aidl/default/Lights.h b/light/aidl/default/Lights.h
index d6d5bf1..cba147f 100644
--- a/light/aidl/default/Lights.h
+++ b/light/aidl/default/Lights.h
@@ -26,7 +26,7 @@
 // Default implementation that reports a few placeholder lights.
 class Lights : public BnLights {
     ndk::ScopedAStatus setLightState(int id, const HwLightState& state) override;
-    ndk::ScopedAStatus getLights(std::vector<HwLight>* types) override;
+    ndk::ScopedAStatus getLights(std::vector<HwLight>* lights) override;
 };
 
 }  // namespace light
diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
index 5ffbd43..34bc962 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
@@ -232,26 +232,24 @@
 //     currently 1Mb, which is shared by all transactions in progress
 //     for the process."
 //
-// Will our representation fit under this limit?  There are two complications:
+// Will our representation fit under this limit?  There are three complications:
 // - Our representation size is just approximate (see sizeForBinder()).
-// - This object may not be the only occupant of the Binder transaction buffer.
+// - This object may not be the only occupant of the Binder transaction buffer
+//   (although our VTS test suite should not be putting multiple objects in the
+//   buffer at once).
+// - IBinder.MAX_IPC_SIZE recommends limiting a transaction to 64 * 1024 bytes.
 // So we'll be very conservative: We want the representation size to be no
-// larger than half the transaction buffer size.
+// larger than half the recommended limit.
 //
 // If our representation grows large enough that it still fits within
 // the transaction buffer but combined with other transactions may
 // exceed the buffer size, then we may see intermittent HAL transport
 // errors.
 static bool exceedsBinderSizeLimit(size_t representationSize) {
-    // Instead of using this fixed buffer size, we might instead be able to use
-    // ProcessState::self()->getMmapSize(). However, this has a potential
-    // problem: The binder/mmap size of the current process does not necessarily
-    // indicate the binder/mmap size of the service (i.e., the other process).
-    // The only way it would be a good indication is if both the current process
-    // and the service use the default size.
-    static const size_t kHalfBufferSize = 1024 * 1024 / 2;
+    // There is no C++ API to retrieve the value of the Java variable IBinder.MAX_IPC_SIZE.
+    static const size_t kHalfMaxIPCSize = 64 * 1024 / 2;
 
-    return representationSize > kHalfBufferSize;
+    return representationSize > kHalfMaxIPCSize;
 }
 
 ///////////////////////// VALIDATE EXECUTION ORDER ////////////////////////////
diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
index 1f4e4ed..dbabbaf 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
@@ -252,26 +252,24 @@
 //     currently 1Mb, which is shared by all transactions in progress
 //     for the process."
 //
-// Will our representation fit under this limit?  There are two complications:
+// Will our representation fit under this limit?  There are three complications:
 // - Our representation size is just approximate (see sizeForBinder()).
-// - This object may not be the only occupant of the Binder transaction buffer.
+// - This object may not be the only occupant of the Binder transaction buffer
+//   (although our VTS test suite should not be putting multiple objects in the
+//   buffer at once).
+// - IBinder.MAX_IPC_SIZE recommends limiting a transaction to 64 * 1024 bytes.
 // So we'll be very conservative: We want the representation size to be no
-// larger than half the transaction buffer size.
+// larger than half the recommended limit.
 //
 // If our representation grows large enough that it still fits within
 // the transaction buffer but combined with other transactions may
 // exceed the buffer size, then we may see intermittent HAL transport
 // errors.
 static bool exceedsBinderSizeLimit(size_t representationSize) {
-    // Instead of using this fixed buffer size, we might instead be able to use
-    // ProcessState::self()->getMmapSize(). However, this has a potential
-    // problem: The binder/mmap size of the current process does not necessarily
-    // indicate the binder/mmap size of the service (i.e., the other process).
-    // The only way it would be a good indication is if both the current process
-    // and the service use the default size.
-    static const size_t kHalfBufferSize = 1024 * 1024 / 2;
+    // There is no C++ API to retrieve the value of the Java variable IBinder.MAX_IPC_SIZE.
+    static const size_t kHalfMaxIPCSize = 64 * 1024 / 2;
 
-    return representationSize > kHalfBufferSize;
+    return representationSize > kHalfMaxIPCSize;
 }
 
 ///////////////////////// VALIDATE EXECUTION ORDER ////////////////////////////
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index 3375602..d7cd6f5 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -291,26 +291,24 @@
 //     currently 1Mb, which is shared by all transactions in progress
 //     for the process."
 //
-// Will our representation fit under this limit?  There are two complications:
+// Will our representation fit under this limit?  There are three complications:
 // - Our representation size is just approximate (see sizeForBinder()).
-// - This object may not be the only occupant of the Binder transaction buffer.
+// - This object may not be the only occupant of the Binder transaction buffer
+//   (although our VTS test suite should not be putting multiple objects in the
+//   buffer at once).
+// - IBinder.MAX_IPC_SIZE recommends limiting a transaction to 64 * 1024 bytes.
 // So we'll be very conservative: We want the representation size to be no
-// larger than half the transaction buffer size.
+// larger than half the recommended limit.
 //
 // If our representation grows large enough that it still fits within
 // the transaction buffer but combined with other transactions may
 // exceed the buffer size, then we may see intermittent HAL transport
 // errors.
 static bool exceedsBinderSizeLimit(size_t representationSize) {
-    // Instead of using this fixed buffer size, we might instead be able to use
-    // ProcessState::self()->getMmapSize(). However, this has a potential
-    // problem: The binder/mmap size of the current process does not necessarily
-    // indicate the binder/mmap size of the service (i.e., the other process).
-    // The only way it would be a good indication is if both the current process
-    // and the service use the default size.
-    static const size_t kHalfBufferSize = 1024 * 1024 / 2;
+    // There is no C++ API to retrieve the value of the Java variable IBinder.MAX_IPC_SIZE.
+    static const size_t kHalfMaxIPCSize = 64 * 1024 / 2;
 
-    return representationSize > kHalfBufferSize;
+    return representationSize > kHalfMaxIPCSize;
 }
 
 ///////////////////////// VALIDATE EXECUTION ORDER ////////////////////////////
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 849ef7b..d8c7cd1 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -308,26 +308,24 @@
 //     currently 1Mb, which is shared by all transactions in progress
 //     for the process."
 //
-// Will our representation fit under this limit?  There are two complications:
+// Will our representation fit under this limit?  There are three complications:
 // - Our representation size is just approximate (see sizeForBinder()).
-// - This object may not be the only occupant of the Binder transaction buffer.
+// - This object may not be the only occupant of the Binder transaction buffer
+//   (although our VTS test suite should not be putting multiple objects in the
+//   buffer at once).
+// - IBinder.MAX_IPC_SIZE recommends limiting a transaction to 64 * 1024 bytes.
 // So we'll be very conservative: We want the representation size to be no
-// larger than half the transaction buffer size.
+// larger than half the recommended limit.
 //
 // If our representation grows large enough that it still fits within
 // the transaction buffer but combined with other transactions may
 // exceed the buffer size, then we may see intermittent HAL transport
 // errors.
 static bool exceedsBinderSizeLimit(size_t representationSize) {
-    // Instead of using this fixed buffer size, we might instead be able to use
-    // ProcessState::self()->getMmapSize(). However, this has a potential
-    // problem: The binder/mmap size of the current process does not necessarily
-    // indicate the binder/mmap size of the service (i.e., the other process).
-    // The only way it would be a good indication is if both the current process
-    // and the service use the default size.
-    static const size_t kHalfBufferSize = 1024 * 1024 / 2;
+    // There is no C++ API to retrieve the value of the Java variable IBinder.MAX_IPC_SIZE.
+    static const size_t kHalfMaxIPCSize = 64 * 1024 / 2;
 
-    return representationSize > kHalfBufferSize;
+    return representationSize > kHalfMaxIPCSize;
 }
 
 ///////////////////////// VALIDATE EXECUTION ORDER ////////////////////////////
diff --git a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
index 060434e..d7baf19 100644
--- a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
@@ -344,26 +344,24 @@
 //     currently 1Mb, which is shared by all transactions in progress
 //     for the process."
 //
-// Will our representation fit under this limit?  There are two complications:
+// Will our representation fit under this limit?  There are three complications:
 // - Our representation size is just approximate (see sizeForBinder()).
-// - This object may not be the only occupant of the Binder transaction buffer.
+// - This object may not be the only occupant of the Binder transaction buffer
+//   (although our VTS test suite should not be putting multiple objects in the
+//   buffer at once).
+// - IBinder.MAX_IPC_SIZE recommends limiting a transaction to 64 * 1024 bytes.
 // So we'll be very conservative: We want the representation size to be no
-// larger than half the transaction buffer size.
+// larger than half the recommended limit.
 //
 // If our representation grows large enough that it still fits within
 // the transaction buffer but combined with other transactions may
 // exceed the buffer size, then we may see intermittent HAL transport
 // errors.
 static bool exceedsBinderSizeLimit(size_t representationSize) {
-    // Instead of using this fixed buffer size, we might instead be able to use
-    // ProcessState::self()->getMmapSize(). However, this has a potential
-    // problem: The binder/mmap size of the current process does not necessarily
-    // indicate the binder/mmap size of the service (i.e., the other process).
-    // The only way it would be a good indication is if both the current process
-    // and the service use the default size.
-    static const size_t kHalfBufferSize = 1024 * 1024 / 2;
+    // There is no C++ API to retrieve the value of the Java variable IBinder.MAX_IPC_SIZE.
+    static const size_t kHalfMaxIPCSize = 64 * 1024 / 2;
 
-    return representationSize > kHalfBufferSize;
+    return representationSize > kHalfMaxIPCSize;
 }
 
 ///////////////////////// VALIDATE EXECUTION ORDER ////////////////////////////
diff --git a/tv/input/OWNERS b/tv/input/OWNERS
new file mode 100644
index 0000000..a02291a
--- /dev/null
+++ b/tv/input/OWNERS
@@ -0,0 +1,4 @@
+hgchen@google.com
+shubang@google.com
+quxiangfang@google.com
+yixiaoluo@google.com
diff --git a/tv/input/aidl/Android.bp b/tv/input/aidl/Android.bp
new file mode 100644
index 0000000..1987174
--- /dev/null
+++ b/tv/input/aidl/Android.bp
@@ -0,0 +1,27 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+aidl_interface {
+    name: "android.hardware.tv.input",
+    vendor_available: true,
+    srcs: ["android/hardware/tv/input/*.aidl"],
+    imports: [
+        "android.hardware.common-V2",
+        "android.media.audio.common.types-V1",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+        },
+        cpp: {
+            enabled: false,
+        },
+    },
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/CableConnectionStatus.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/CableConnectionStatus.aidl
new file mode 100644
index 0000000..a48bdb1
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/CableConnectionStatus.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.input;
+@Backing(type="int") @VintfStability
+enum CableConnectionStatus {
+  UNKNOWN = 0,
+  CONNECTED = 1,
+  DISCONNECTED = 2,
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInput.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInput.aidl
new file mode 100644
index 0000000..f8d5e05
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInput.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.input;
+@VintfStability
+interface ITvInput {
+  void closeStream(in int deviceId, in int streamId);
+  android.hardware.tv.input.TvStreamConfig[] getStreamConfigurations(in int deviceId);
+  android.hardware.common.NativeHandle openStream(in int deviceId, in int streamId);
+  void setCallback(in android.hardware.tv.input.ITvInputCallback callback);
+  const int STATUS_UNKNOWN = 1;
+  const int STATUS_NO_RESOURCE = 2;
+  const int STATUS_INVALID_ARGUMENTS = 3;
+  const int STATUS_INVALID_STATE = 4;
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInputCallback.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInputCallback.aidl
new file mode 100644
index 0000000..7f2aff6
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/ITvInputCallback.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.input;
+@VintfStability
+interface ITvInputCallback {
+  void notify(in android.hardware.tv.input.TvInputEvent event);
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputDeviceInfo.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputDeviceInfo.aidl
new file mode 100644
index 0000000..d095146
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputDeviceInfo.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.input;
+@VintfStability
+parcelable TvInputDeviceInfo {
+  int deviceId;
+  android.hardware.tv.input.TvInputType type;
+  int portId;
+  android.hardware.tv.input.CableConnectionStatus cableConnectionStatus;
+  android.media.audio.common.AudioDevice audioDevice;
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEvent.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEvent.aidl
new file mode 100644
index 0000000..cfa8a34
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEvent.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.input;
+@VintfStability
+parcelable TvInputEvent {
+  android.hardware.tv.input.TvInputEventType type;
+  android.hardware.tv.input.TvInputDeviceInfo deviceInfo;
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEventType.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEventType.aidl
new file mode 100644
index 0000000..a9f518a
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputEventType.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.input;
+@Backing(type="int") @VintfStability
+enum TvInputEventType {
+  DEVICE_AVAILABLE = 1,
+  DEVICE_UNAVAILABLE = 2,
+  STREAM_CONFIGURATIONS_CHANGED = 3,
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputType.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputType.aidl
new file mode 100644
index 0000000..7e44a7d
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvInputType.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.input;
+@Backing(type="int") @VintfStability
+enum TvInputType {
+  OTHER = 1,
+  TUNER = 2,
+  COMPOSITE = 3,
+  SVIDEO = 4,
+  SCART = 5,
+  COMPONENT = 6,
+  VGA = 7,
+  DVI = 8,
+  HDMI = 9,
+  DISPLAY_PORT = 10,
+}
diff --git a/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvStreamConfig.aidl b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvStreamConfig.aidl
new file mode 100644
index 0000000..8378ff3
--- /dev/null
+++ b/tv/input/aidl/aidl_api/android.hardware.tv.input/current/android/hardware/tv/input/TvStreamConfig.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.tv.input;
+@VintfStability
+parcelable TvStreamConfig {
+  int streamId;
+  int maxVideoWidth;
+  int maxVideoHeight;
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/CableConnectionStatus.aidl b/tv/input/aidl/android/hardware/tv/input/CableConnectionStatus.aidl
new file mode 100644
index 0000000..64b79dd
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/CableConnectionStatus.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.input;
+
+/**
+ * Status of cable connection.
+ * This status is for devices having availability to detect the cable in a mechanical way,
+ * regardless of whether the connected external device is electrically on or not.
+ * If the device does not have such capability, you must use UNKNOWN.
+ */
+@VintfStability
+@Backing(type="int")
+enum CableConnectionStatus {
+    UNKNOWN = 0,
+    CONNECTED = 1,
+    DISCONNECTED = 2,
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/ITvInput.aidl b/tv/input/aidl/android/hardware/tv/input/ITvInput.aidl
new file mode 100644
index 0000000..31d6586
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/ITvInput.aidl
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.input;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.tv.input.ITvInputCallback;
+import android.hardware.tv.input.TvStreamConfig;
+
+@VintfStability
+interface ITvInput {
+    /**
+     * ServiceSpecificException values for ITvInput requests
+     */
+    const int STATUS_UNKNOWN = 1;
+    const int STATUS_NO_RESOURCE = 2;
+    const int STATUS_INVALID_ARGUMENTS = 3;
+    const int STATUS_INVALID_STATE = 4;
+
+    /**
+     * Closes a specific stream in a device.
+     *
+     * @param deviceId Device ID for the stream to close.
+     * @param streamId Stream ID for the stream to close.
+     * @throws ServiceSpecificException with values from the ITvInput::STATUS_* constants
+     */
+    void closeStream(in int deviceId, in int streamId);
+
+    /**
+     * Gets stream configurations for a specific device.
+     *
+     * The configs object is valid only until the next
+     * STREAM_CONFIGURATIONS_CHANGED event.
+     *
+     * @param deviceId Device ID for the configurations.
+     * @return the array of available configurations.
+     * @throws ServiceSpecificException with values from the ITvInput::STATUS_* constants
+     */
+    TvStreamConfig[] getStreamConfigurations(in int deviceId);
+
+    /**
+     * Opens a specific stream in a device.
+     *
+     * @param deviceId Device ID for the stream to open.
+     * @param streamId Stream ID for the stream to open. Must be one of the
+     *         stream IDs returned from getStreamConfigurations().
+     * @return the handle for sideband stream.
+     * @throws ServiceSpecificException with values from the ITvInput::STATUS_* constants
+     */
+    NativeHandle openStream(in int deviceId, in int streamId);
+
+    /**
+     * Sets a callback for events.
+     *
+     * Note that initially no device is available in the client side, so the
+     * implementation must notify all the currently available devices including
+     * static devices via callback once callback is set.
+     *
+     * @param callback Callback object to pass events.
+     * @throws ServiceSpecificException with values from the ITvInput::STATUS_* constants
+     */
+    void setCallback(in ITvInputCallback callback);
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/ITvInputCallback.aidl b/tv/input/aidl/android/hardware/tv/input/ITvInputCallback.aidl
new file mode 100644
index 0000000..fc7492d
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/ITvInputCallback.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.input;
+
+import android.hardware.tv.input.TvInputEvent;
+
+@VintfStability
+interface ITvInputCallback {
+    /**
+     * Notifies the client that an event has occurred. For possible event types,
+     * check TvInputEventType.
+     *
+     * @param event Event passed to the client.
+     */
+    void notify(in TvInputEvent event);
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/TvInputDeviceInfo.aidl b/tv/input/aidl/android/hardware/tv/input/TvInputDeviceInfo.aidl
new file mode 100644
index 0000000..2782e90
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/TvInputDeviceInfo.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.input;
+
+import android.hardware.tv.input.CableConnectionStatus;
+import android.hardware.tv.input.TvInputType;
+import android.media.audio.common.AudioDevice;
+
+@VintfStability
+parcelable TvInputDeviceInfo {
+    int deviceId;
+    TvInputType type;
+
+    /* HDMI port ID number. e.g. 2 for HDMI 2. */
+    int portId;
+
+    /* Cable connection status. */
+    CableConnectionStatus cableConnectionStatus;
+
+    /* Audio device info. */
+    AudioDevice audioDevice;
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/TvInputEvent.aidl b/tv/input/aidl/android/hardware/tv/input/TvInputEvent.aidl
new file mode 100644
index 0000000..66ca7aa
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/TvInputEvent.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.input;
+
+import android.hardware.tv.input.TvInputDeviceInfo;
+import android.hardware.tv.input.TvInputEventType;
+
+@VintfStability
+parcelable TvInputEvent {
+    TvInputEventType type;
+
+    /**
+     * TvInputEventType::DEVICE_AVAILABLE: all fields are relevant.
+     * TvInputEventType::DEVICE_UNAVAILABLE: only deviceId is relevant.
+     * TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: only deviceId is relevant.
+     */
+    TvInputDeviceInfo deviceInfo;
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/TvInputEventType.aidl b/tv/input/aidl/android/hardware/tv/input/TvInputEventType.aidl
new file mode 100644
index 0000000..fcbc3c2
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/TvInputEventType.aidl
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.input;
+
+@VintfStability
+@Backing(type="int")
+enum TvInputEventType {
+    /**
+     * Hardware notifies the framework that a device is available.
+     *
+     * Note that DEVICE_AVAILABLE and DEVICE_UNAVAILABLE events do not represent
+     * hotplug events (i.e. plugging cable into or out of the physical port).
+     * These events notify the framework whether the port is available or not.
+     * For a concrete example, when a user plugs in or pulls out the HDMI cable
+     * from a HDMI port, it does not generate DEVICE_AVAILABLE and/or
+     * DEVICE_UNAVAILABLE events. However, if a user inserts a pluggable USB
+     * tuner into the Android device, it must generate a DEVICE_AVAILABLE event
+     * and when the port is removed, it must generate a DEVICE_UNAVAILABLE
+     * event.
+     *
+     * For hotplug events, please see STREAM_CONFIGURATION_CHANGED for more
+     * details.
+     *
+     * HAL implementation must register devices by using this event when the
+     * device boots up. The framework must recognize device reported via this
+     * event only.
+     */
+    DEVICE_AVAILABLE = 1,
+
+    /**
+     * Hardware notifies the framework that a device is unavailable.
+     *
+     * HAL implementation must generate this event when a device registered
+     * by DEVICE_AVAILABLE is no longer available. For example,
+     * the event can indicate that a USB tuner is plugged out from the Android
+     * device.
+     *
+     * Note that this event is not for indicating cable plugged out of the port;
+     * for that purpose, the implementation must use
+     * STREAM_CONFIGURATION_CHANGED event. This event represents the port itself
+     * being no longer available.
+     */
+    DEVICE_UNAVAILABLE = 2,
+
+    /**
+     * Stream configurations are changed. Client must regard all open streams
+     * at the specific device are closed, and must call
+     * getStreamConfigurations() again, opening some of them if necessary.
+     *
+     * HAL implementation must generate this event when the available stream
+     * configurations change for any reason. A typical use case of this event
+     * is to notify the framework that the input signal has changed resolution,
+     * or that the cable is plugged out so that the number of available streams
+     * is 0.
+     *
+     * The implementation must use this event to indicate hotplug status of the
+     * port. the framework regards input devices with no available streams as
+     * disconnected, so the implementation can generate this event with no
+     * available streams to indicate that this device is disconnected, and vice
+     * versa.
+     */
+    STREAM_CONFIGURATIONS_CHANGED = 3,
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/TvInputType.aidl b/tv/input/aidl/android/hardware/tv/input/TvInputType.aidl
new file mode 100644
index 0000000..a0f8270
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/TvInputType.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.input;
+
+/**
+ * Type of physical TV input.
+ */
+@VintfStability
+@Backing(type="int")
+enum TvInputType {
+    OTHER = 1,
+    TUNER = 2,
+    COMPOSITE = 3,
+    SVIDEO = 4,
+    SCART = 5,
+    COMPONENT = 6,
+    VGA = 7,
+    DVI = 8,
+    HDMI = 9,
+    DISPLAY_PORT = 10,
+}
diff --git a/tv/input/aidl/android/hardware/tv/input/TvStreamConfig.aidl b/tv/input/aidl/android/hardware/tv/input/TvStreamConfig.aidl
new file mode 100644
index 0000000..af86953
--- /dev/null
+++ b/tv/input/aidl/android/hardware/tv/input/TvStreamConfig.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.tv.input;
+
+@VintfStability
+parcelable TvStreamConfig {
+    int streamId;
+
+    /* Maximum video width in pixel. */
+    int maxVideoWidth;
+
+    /* Maximum video height in pixel. */
+    int maxVideoHeight;
+}
diff --git a/tv/input/aidl/default/Android.bp b/tv/input/aidl/default/Android.bp
new file mode 100644
index 0000000..66148c8
--- /dev/null
+++ b/tv/input/aidl/default/Android.bp
@@ -0,0 +1,31 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_binary {
+    name: "android.hardware.tv.input-service.example",
+    relative_install_path: "hw",
+    init_rc: ["input-default.rc"],
+    vintf_fragments: ["input-default.xml"],
+    vendor: true,
+    srcs: [
+        "TvInput.cpp",
+        "service.cpp",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libutils",
+        "libcutils",
+        "libbinder_ndk",
+        "android.hardware.tv.input-V1-ndk",
+    ],
+}
diff --git a/tv/input/aidl/default/TvInput.cpp b/tv/input/aidl/default/TvInput.cpp
new file mode 100644
index 0000000..6c3a138
--- /dev/null
+++ b/tv/input/aidl/default/TvInput.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.input-service.example"
+
+#include <utils/Log.h>
+
+#include "TvInput.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace tv {
+namespace input {
+
+TvInput::TvInput() {}
+
+void TvInput::init() {
+    // Set up TvInputDeviceInfo and TvStreamConfig
+    mDeviceInfos[0] = shared_ptr<TvInputDeviceInfoWrapper>(
+            new TvInputDeviceInfoWrapper(0, TvInputType::TUNER, true));
+    mDeviceInfos[1] = shared_ptr<TvInputDeviceInfoWrapper>(
+            new TvInputDeviceInfoWrapper(1, TvInputType::HDMI, true));
+    mDeviceInfos[3] = shared_ptr<TvInputDeviceInfoWrapper>(
+            new TvInputDeviceInfoWrapper(3, TvInputType::DISPLAY_PORT, true));
+
+    mStreamConfigs[0] = {
+            {1, shared_ptr<TvStreamConfigWrapper>(new TvStreamConfigWrapper(1, 720, 1080, false))}};
+    mStreamConfigs[1] = {{11, shared_ptr<TvStreamConfigWrapper>(
+                                      new TvStreamConfigWrapper(11, 360, 480, false))}};
+    mStreamConfigs[3] = {{5, shared_ptr<TvStreamConfigWrapper>(
+                                     new TvStreamConfigWrapper(5, 1080, 1920, false))}};
+}
+
+::ndk::ScopedAStatus TvInput::setCallback(const shared_ptr<ITvInputCallback>& in_callback) {
+    ALOGV("%s", __FUNCTION__);
+
+    mCallback = in_callback;
+
+    TvInputEvent event;
+    event.type = TvInputEventType::DEVICE_AVAILABLE;
+
+    event.deviceInfo = mDeviceInfos[0]->deviceInfo;
+    mCallback->notify(event);
+
+    event.deviceInfo = mDeviceInfos[1]->deviceInfo;
+    mCallback->notify(event);
+
+    event.deviceInfo = mDeviceInfos[3]->deviceInfo;
+    mCallback->notify(event);
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TvInput::getStreamConfigurations(int32_t in_deviceId,
+                                                      vector<TvStreamConfig>* _aidl_return) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (mStreamConfigs.count(in_deviceId) == 0) {
+        ALOGW("Device with id %d isn't available", in_deviceId);
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_ARGUMENTS);
+    }
+
+    for (auto const& iconfig : mStreamConfigs[in_deviceId]) {
+        _aidl_return->push_back(iconfig.second->streamConfig);
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TvInput::openStream(int32_t in_deviceId, int32_t in_streamId,
+                                         NativeHandle* _aidl_return) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (mStreamConfigs.count(in_deviceId) == 0 ||
+        mStreamConfigs[in_deviceId].count(in_streamId) == 0) {
+        ALOGW("Stream with device id %d, stream id %d isn't available", in_deviceId, in_streamId);
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_ARGUMENTS);
+    }
+    if (mStreamConfigs[in_deviceId][in_streamId]->isOpen) {
+        ALOGW("Stream with device id %d, stream id %d is already opened", in_deviceId, in_streamId);
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_STATE);
+    }
+    mStreamConfigs[in_deviceId][in_streamId]->handle = createNativeHandle(in_streamId);
+    mStreamConfigs[in_deviceId][in_streamId]->isOpen = true;
+    NativeHandle aidlHandle = makeToAidl(mStreamConfigs[in_deviceId][in_streamId]->handle);
+    _aidl_return = &aidlHandle;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TvInput::closeStream(int32_t in_deviceId, int32_t in_streamId) {
+    ALOGV("%s", __FUNCTION__);
+
+    if (mStreamConfigs.count(in_deviceId) == 0 ||
+        mStreamConfigs[in_deviceId].count(in_streamId) == 0) {
+        ALOGW("Stream with device id %d, stream id %d isn't available", in_deviceId, in_streamId);
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_ARGUMENTS);
+    }
+    if (!mStreamConfigs[in_deviceId][in_streamId]->isOpen) {
+        ALOGW("Stream with device id %d, stream id %d is already closed", in_deviceId, in_streamId);
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(STATUS_INVALID_STATE);
+    }
+    releaseNativeHandle(mStreamConfigs[in_deviceId][in_streamId]->handle);
+    mStreamConfigs[in_deviceId][in_streamId]->handle = nullptr;
+    mStreamConfigs[in_deviceId][in_streamId]->isOpen = false;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+native_handle_t* TvInput::createNativeHandle(int fd) {
+    native_handle_t* nativeHandle = native_handle_create(1, 0);
+    if (nativeHandle == nullptr) {
+        ALOGE("[TVInput] Failed to create native_handle %d", errno);
+        return nullptr;
+    }
+    if (nativeHandle->numFds > 0) {
+        nativeHandle->data[0] = dup(fd);
+    }
+    return nativeHandle;
+}
+
+void TvInput::releaseNativeHandle(native_handle_t* handle) {
+    native_handle_close(handle);
+    native_handle_delete(handle);
+}
+
+}  // namespace input
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/tv/input/aidl/default/TvInput.h b/tv/input/aidl/default/TvInput.h
new file mode 100644
index 0000000..a72bca3
--- /dev/null
+++ b/tv/input/aidl/default/TvInput.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/tv/input/BnTvInput.h>
+#include <utils/KeyedVector.h>
+
+#include <map>
+#include "TvInputDeviceInfoWrapper.h"
+#include "TvStreamConfigWrapper.h"
+
+using namespace android;
+using namespace std;
+using ::aidl::android::hardware::common::NativeHandle;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace tv {
+namespace input {
+
+class TvInput : public BnTvInput {
+  public:
+    TvInput();
+
+    ::ndk::ScopedAStatus setCallback(const shared_ptr<ITvInputCallback>& in_callback) override;
+    ::ndk::ScopedAStatus getStreamConfigurations(int32_t in_deviceId,
+                                                 vector<TvStreamConfig>* _aidl_return) override;
+    ::ndk::ScopedAStatus openStream(int32_t in_deviceId, int32_t in_streamId,
+                                    NativeHandle* _aidl_return) override;
+    ::ndk::ScopedAStatus closeStream(int32_t in_deviceId, int32_t in_streamId) override;
+
+    void init();
+
+  private:
+    native_handle_t* createNativeHandle(int fd);
+    void releaseNativeHandle(native_handle_t* handle);
+
+    shared_ptr<ITvInputCallback> mCallback;
+    map<int32_t, shared_ptr<TvInputDeviceInfoWrapper>> mDeviceInfos;
+    map<int32_t, map<int32_t, shared_ptr<TvStreamConfigWrapper>>> mStreamConfigs;
+};
+
+}  // namespace input
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/tv/input/aidl/default/TvInputDeviceInfoWrapper.h b/tv/input/aidl/default/TvInputDeviceInfoWrapper.h
new file mode 100644
index 0000000..d844cc8
--- /dev/null
+++ b/tv/input/aidl/default/TvInputDeviceInfoWrapper.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/tv/input/TvInputDeviceInfo.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace tv {
+namespace input {
+
+class TvInputDeviceInfoWrapper {
+  public:
+    TvInputDeviceInfoWrapper() {}
+    TvInputDeviceInfoWrapper(int32_t deviceId_, TvInputType type_, bool isAvailable_) {
+        deviceInfo.deviceId = deviceId_;
+        deviceInfo.type = type_;
+        isAvailable = isAvailable_;
+    }
+
+    TvInputDeviceInfo deviceInfo;
+    bool isAvailable;
+};
+}  // namespace input
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/tv/input/aidl/default/TvStreamConfigWrapper.h b/tv/input/aidl/default/TvStreamConfigWrapper.h
new file mode 100644
index 0000000..05c7ca3
--- /dev/null
+++ b/tv/input/aidl/default/TvStreamConfigWrapper.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/tv/input/TvStreamConfig.h>
+#include <aidlcommonsupport/NativeHandle.h>
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace tv {
+namespace input {
+
+class TvStreamConfigWrapper {
+  public:
+    TvStreamConfigWrapper() {}
+    TvStreamConfigWrapper(int32_t streamId_, int32_t maxVideoWidth_, int32_t maxVideoHeight_,
+                          bool isOpen_) {
+        streamConfig.streamId = streamId_;
+        streamConfig.maxVideoWidth = maxVideoWidth_;
+        streamConfig.maxVideoHeight = maxVideoHeight_;
+        isOpen = isOpen_;
+        handle = nullptr;
+    }
+
+    TvStreamConfig streamConfig;
+    bool isOpen;
+    native_handle_t* handle;
+};
+}  // namespace input
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/tv/input/aidl/default/input-default.rc b/tv/input/aidl/default/input-default.rc
new file mode 100644
index 0000000..1958b5c
--- /dev/null
+++ b/tv/input/aidl/default/input-default.rc
@@ -0,0 +1,5 @@
+service vendor.input-default /vendor/bin/hw/android.hardware.tv.input-service.example
+    interface aidl android.hardware.tv.input.ITvInput/default
+    class hal
+    user system
+    group system
diff --git a/tv/input/aidl/default/input-default.xml b/tv/input/aidl/default/input-default.xml
new file mode 100644
index 0000000..38ba151
--- /dev/null
+++ b/tv/input/aidl/default/input-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.tv.input</name>
+        <fqname>ITvInput/default</fqname>
+    </hal>
+</manifest>
\ No newline at end of file
diff --git a/tv/input/aidl/default/service.cpp b/tv/input/aidl/default/service.cpp
new file mode 100644
index 0000000..1021206
--- /dev/null
+++ b/tv/input/aidl/default/service.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.input-service.example"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <utils/Log.h>
+
+#include "TvInput.h"
+
+using ::aidl::android::hardware::tv::input::TvInput;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(8);
+    std::shared_ptr<TvInput> tvInput = ndk::SharedRefBase::make<TvInput>();
+    tvInput->init();
+
+    const std::string instance = std::string() + TvInput::descriptor + "/default";
+    binder_status_t status =
+            AServiceManager_addService(tvInput->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reached
+}
diff --git a/tv/input/aidl/vts/functional/Android.bp b/tv/input/aidl/vts/functional/Android.bp
new file mode 100644
index 0000000..9829b6d
--- /dev/null
+++ b/tv/input/aidl/vts/functional/Android.bp
@@ -0,0 +1,29 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+    name: "VtsHalTvInputTargetTest",
+    defaults: ["VtsHalTargetTestDefaults","use_libaidlvintf_gtest_helper_static",],
+    srcs: ["VtsHalTvInputTargetTest.cpp"],
+    static_libs: [
+        "android.hardware.tv.input-V1-ndk",
+        "android.media.audio.common.types-V1-ndk",
+        "android.hardware.common-V2-ndk",
+        "libaidlcommonsupport",
+    ],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+    shared_libs: [
+        "libbinder_ndk",
+        "libvndksupport",
+    ],
+    require_root: true,
+}
diff --git a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
new file mode 100644
index 0000000..ec83e29
--- /dev/null
+++ b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VtsHalTvInputTargetTest.h"
+
+#include <android-base/properties.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_process.h>
+#include <android/binder_status.h>
+
+using namespace VtsHalTvInputTargetTest;
+
+TvInputAidlTest::TvInputCallback::TvInputCallback(shared_ptr<TvInputAidlTest> parent)
+    : parent_(parent) {}
+
+::ndk::ScopedAStatus TvInputAidlTest::TvInputCallback::notify(const TvInputEvent& in_event) {
+    unique_lock<mutex> lock(parent_->mutex_);
+
+    switch (in_event.type) {
+        case TvInputEventType::DEVICE_AVAILABLE:
+            parent_->onDeviceAvailable(in_event.deviceInfo);
+            break;
+        case TvInputEventType::DEVICE_UNAVAILABLE:
+            parent_->onDeviceUnavailable(in_event.deviceInfo.deviceId);
+            break;
+        case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
+            parent_->onStreamConfigurationsChanged(in_event.deviceInfo.deviceId);
+            break;
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+void TvInputAidlTest::SetUp() {
+    if (AServiceManager_isDeclared(GetParam().c_str())) {
+        ::ndk::SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str()));
+        tv_input_ = ITvInput::fromBinder(binder);
+    } else {
+        tv_input_ = nullptr;
+    }
+    ASSERT_NE(tv_input_, nullptr);
+
+    tv_input_callback_ =
+            ::ndk::SharedRefBase::make<TvInputCallback>(shared_ptr<TvInputAidlTest>(this));
+    ASSERT_NE(tv_input_callback_, nullptr);
+
+    tv_input_->setCallback(tv_input_callback_);
+    // All events received within the timeout should be handled.
+    sleep(WAIT_FOR_EVENT_TIMEOUT);
+}
+
+void TvInputAidlTest::TearDown() {
+    tv_input_ = nullptr;
+}
+
+void TvInputAidlTest::onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
+    ALOGD("onDeviceAvailable for device id %d", deviceInfo.deviceId);
+    device_info_.add(deviceInfo.deviceId, deviceInfo);
+}
+
+void TvInputAidlTest::onDeviceUnavailable(int32_t deviceId) {
+    ALOGD("onDeviceUnavailable for device id %d", deviceId);
+    device_info_.removeItem(deviceId);
+    stream_config_.removeItem(deviceId);
+}
+
+::ndk::ScopedAStatus TvInputAidlTest::onStreamConfigurationsChanged(int32_t deviceId) {
+    ALOGD("onStreamConfigurationsChanged for device id %d", deviceId);
+    return updateStreamConfigurations(deviceId);
+}
+
+::ndk::ScopedAStatus TvInputAidlTest::updateStreamConfigurations(int32_t deviceId) {
+    stream_config_.removeItem(deviceId);
+    vector<TvStreamConfig> list;
+    ::ndk::ScopedAStatus status = tv_input_->getStreamConfigurations(deviceId, &list);
+    if (status.isOk()) {
+        stream_config_.add(deviceId, list);
+    }
+    return status;
+}
+
+void TvInputAidlTest::updateAllStreamConfigurations() {
+    for (size_t i = 0; i < device_info_.size(); i++) {
+        int32_t device_id = device_info_.keyAt(i);
+        updateStreamConfigurations(device_id);
+    }
+}
+
+vector<size_t> TvInputAidlTest::getConfigIndices() {
+    vector<size_t> indices;
+    for (size_t i = 0; i < stream_config_.size(); i++) {
+        if (stream_config_.valueAt(i).size() != 0) {
+            indices.push_back(i);
+        }
+    }
+    return indices;
+}
+
+int32_t TvInputAidlTest::getNumNotIn(vector<int32_t>& nums) {
+    int32_t result = DEFAULT_ID;
+    int32_t size = static_cast<int32_t>(nums.size());
+    for (int32_t i = 0; i < size; i++) {
+        // Put every element to its target position, if possible.
+        int32_t target_pos = nums[i];
+        while (target_pos >= 0 && target_pos < size && i != target_pos &&
+               nums[i] != nums[target_pos]) {
+            swap(nums[i], nums[target_pos]);
+            target_pos = nums[i];
+        }
+    }
+
+    for (int32_t i = 0; i < size; i++) {
+        if (nums[i] != i) {
+            return i;
+        }
+    }
+    return result;
+}
+
+/*
+ * GetStreamConfigTest:
+ * Calls updateStreamConfigurations() for each existing device
+ * Checks returned results
+ */
+TEST_P(TvInputAidlTest, GetStreamConfigTest) {
+    unique_lock<mutex> lock(mutex_);
+
+    for (size_t i = 0; i < device_info_.size(); i++) {
+        int32_t device_id = device_info_.keyAt(i);
+        ALOGD("GetStreamConfigTest: device_id=%d", device_id);
+        ASSERT_TRUE(updateStreamConfigurations(device_id).isOk());
+    }
+}
+
+/*
+ * OpenAndCloseStreamTest:
+ * Calls openStream() and then closeStream() for each existing stream
+ * Checks returned results
+ */
+TEST_P(TvInputAidlTest, OpenAndCloseStreamTest) {
+    unique_lock<mutex> lock(mutex_);
+
+    updateAllStreamConfigurations();
+
+    for (size_t j = 0; j < stream_config_.size(); j++) {
+        int32_t device_id = stream_config_.keyAt(j);
+        vector<TvStreamConfig> config = stream_config_.valueAt(j);
+        for (size_t i = 0; i < config.size(); i++) {
+            int32_t stream_id = config[i].streamId;
+            ALOGD("OpenAndCloseStreamTest: open stream, device_id=%d, stream_id=%d", device_id,
+                  stream_id);
+            ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle_).isOk());
+            ALOGD("OpenAndCloseStreamTest: close stream, device_id=%d, stream_id=%d", device_id,
+                  stream_id);
+            ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).isOk());
+        }
+    }
+}
+
+/*
+ * InvalidDeviceIdTest:
+ * Calls updateStreamConfigurations(), openStream(), and closeStream()
+ * for a non-existing device
+ * Checks returned results
+ * The results should be ITvInput::STATUS_INVALID_ARGUMENTS
+ */
+TEST_P(TvInputAidlTest, InvalidDeviceIdTest) {
+    unique_lock<mutex> lock(mutex_);
+
+    vector<int32_t> device_ids;
+    for (size_t i = 0; i < device_info_.size(); i++) {
+        device_ids.push_back(device_info_.keyAt(i));
+    }
+    // Get a non-existing device ID.
+    int32_t id = getNumNotIn(device_ids);
+    ALOGD("InvalidDeviceIdTest: update stream config, device_id=%d", id);
+    ASSERT_TRUE(updateStreamConfigurations(id).getServiceSpecificError() ==
+                ITvInput::STATUS_INVALID_ARGUMENTS);
+
+    int32_t stream_id = 0;
+
+    ALOGD("InvalidDeviceIdTest: open stream, device_id=%d, stream_id=%d", id, stream_id);
+    ASSERT_TRUE(tv_input_->openStream(id, stream_id, &handle_).getServiceSpecificError() ==
+                ITvInput::STATUS_INVALID_ARGUMENTS);
+
+    ALOGD("InvalidDeviceIdTest: close stream, device_id=%d, stream_id=%d", id, stream_id);
+    ASSERT_TRUE(tv_input_->closeStream(id, stream_id).getServiceSpecificError() ==
+                ITvInput::STATUS_INVALID_ARGUMENTS);
+}
+
+/*
+ * InvalidStreamIdTest:
+ * Calls openStream(), and closeStream() for a non-existing stream
+ * Checks returned results
+ * The results should be ITvInput::STATUS_INVALID_ARGUMENTS
+ */
+TEST_P(TvInputAidlTest, InvalidStreamIdTest) {
+    unique_lock<mutex> lock(mutex_);
+
+    if (device_info_.isEmpty()) {
+        return;
+    }
+    updateAllStreamConfigurations();
+
+    int32_t device_id = device_info_.keyAt(0);
+    // Get a non-existing stream ID.
+    int32_t id = DEFAULT_ID;
+    if (stream_config_.indexOfKey(device_id) >= 0) {
+        vector<int32_t> stream_ids;
+        vector<TvStreamConfig> config = stream_config_.valueFor(device_id);
+        for (size_t i = 0; i < config.size(); i++) {
+            stream_ids.push_back(config[i].streamId);
+        }
+        id = getNumNotIn(stream_ids);
+    }
+
+    ALOGD("InvalidStreamIdTest: open stream, device_id=%d, stream_id=%d", device_id, id);
+    ASSERT_TRUE(tv_input_->openStream(device_id, id, &handle_).getServiceSpecificError() ==
+                ITvInput::STATUS_INVALID_ARGUMENTS);
+
+    ALOGD("InvalidStreamIdTest: close stream, device_id=%d, stream_id=%d", device_id, id);
+    ASSERT_TRUE(tv_input_->closeStream(device_id, id).getServiceSpecificError() ==
+                ITvInput::STATUS_INVALID_ARGUMENTS);
+}
+
+/*
+ * OpenAnOpenedStreamsTest:
+ * Calls openStream() twice for a stream (if any)
+ * Checks returned results
+ * The result of the second call should be ITvInput::STATUS_INVALID_STATE
+ */
+TEST_P(TvInputAidlTest, OpenAnOpenedStreamsTest) {
+    unique_lock<mutex> lock(mutex_);
+
+    updateAllStreamConfigurations();
+    vector<size_t> indices = getConfigIndices();
+    if (indices.empty()) {
+        return;
+    }
+    int32_t device_id = stream_config_.keyAt(indices[0]);
+    int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
+
+    ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
+    ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle_).isOk());
+
+    ALOGD("OpenAnOpenedStreamsTest: open stream, device_id=%d, stream_id=%d", device_id, stream_id);
+    ASSERT_TRUE(tv_input_->openStream(device_id, stream_id, &handle_).getServiceSpecificError() ==
+                ITvInput::STATUS_INVALID_STATE);
+
+    // close stream as subsequent tests assume no open streams
+    ALOGD("OpenAnOpenedStreamsTest: close stream, device_id=%d, stream_id=%d", device_id,
+          stream_id);
+    ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).isOk());
+}
+
+/*
+ * CloseStreamBeforeOpenTest:
+ * Calls closeStream() without calling openStream() for a stream (if any)
+ * Checks the returned result
+ * The result should be ITvInput::STATUS_INVALID_STATE
+ */
+TEST_P(TvInputAidlTest, CloseStreamBeforeOpenTest) {
+    unique_lock<mutex> lock(mutex_);
+
+    updateAllStreamConfigurations();
+    vector<size_t> indices = getConfigIndices();
+    if (indices.empty()) {
+        return;
+    }
+    int32_t device_id = stream_config_.keyAt(indices[0]);
+    int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
+
+    ALOGD("CloseStreamBeforeOpenTest: close stream, device_id=%d, stream_id=%d", device_id,
+          stream_id);
+    ASSERT_TRUE(tv_input_->closeStream(device_id, stream_id).getServiceSpecificError() ==
+                ITvInput::STATUS_INVALID_STATE);
+}
+
+INSTANTIATE_TEST_SUITE_P(PerInstance, TvInputAidlTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(ITvInput::descriptor)),
+                         android::PrintInstanceNameToString);
+
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TvInputAidlTest);
diff --git a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h
new file mode 100644
index 0000000..c76e568
--- /dev/null
+++ b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/binder_manager.h>
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <aidl/android/hardware/tv/input/BnTvInputCallback.h>
+#include <aidl/android/hardware/tv/input/ITvInput.h>
+#include <aidl/android/hardware/tv/input/TvInputDeviceInfo.h>
+#include <aidl/android/hardware/tv/input/TvInputEvent.h>
+#include <aidl/android/hardware/tv/input/TvStreamConfig.h>
+
+#include <log/log.h>
+#include <utils/KeyedVector.h>
+
+using namespace aidl::android::hardware::tv::input;
+using namespace std;
+
+using ::aidl::android::hardware::common::NativeHandle;
+
+#define WAIT_FOR_EVENT_TIMEOUT 5
+#define DEFAULT_ID INT32_MIN
+
+namespace VtsHalTvInputTargetTest {
+
+class TvInputAidlTest : public testing::TestWithParam<string> {
+  public:
+    class TvInputCallback : public BnTvInputCallback {
+      public:
+        TvInputCallback(shared_ptr<TvInputAidlTest> parent);
+        ::ndk::ScopedAStatus notify(const TvInputEvent& in_event) override;
+
+      private:
+        shared_ptr<TvInputAidlTest> parent_;
+    };
+
+    virtual void SetUp() override;
+    virtual void TearDown() override;
+
+    /* Called when a DEVICE_AVAILABLE event is received. */
+    void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo);
+
+    /* Called when a DEVICE_UNAVAILABLE event is received. */
+    void onDeviceUnavailable(int32_t deviceId);
+
+    /* Called when a STREAM_CONFIGURATIONS_CHANGED event is received. */
+    ::ndk::ScopedAStatus onStreamConfigurationsChanged(int32_t deviceId);
+
+    /* Gets and updates the stream configurations for a device. */
+    ::ndk::ScopedAStatus updateStreamConfigurations(int32_t deviceId);
+
+    /* Gets and updates the stream configurations for all existing devices. */
+    void updateAllStreamConfigurations();
+
+    /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
+    vector<size_t> getConfigIndices();
+
+    /*
+     * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums).
+     * Otherwise, returns the smallest missing non-negative integer.
+     */
+    int32_t getNumNotIn(vector<int32_t>& nums);
+
+  protected:
+    shared_ptr<ITvInput> tv_input_;
+    shared_ptr<TvInputCallback> tv_input_callback_;
+    android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_;
+    android::KeyedVector<int32_t, vector<TvStreamConfig>> stream_config_;
+    mutex mutex_;
+    NativeHandle handle_;
+};
+
+}  // namespace VtsHalTvInputTargetTest