Adds additional host info exchanges in Context Hub HAL

Bug: 194287786
Test: Run VTS
Change-Id: I5459e44f752cd04bc1bec3b5e99f398be9f4ce11
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/HostEndpointInfo.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/HostEndpointInfo.aidl
new file mode 100644
index 0000000..7da4482
--- /dev/null
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/HostEndpointInfo.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.contexthub;
+@VintfStability
+parcelable HostEndpointInfo {
+  char hostEndpointId;
+  android.hardware.contexthub.HostEndpointInfo.Type type;
+  @nullable String[] packageName;
+  @nullable String[] attributionTag;
+  @Backing(type="int") @VintfStability
+  enum Type {
+    TYPE_FRAMEWORK = 1,
+    TYPE_APP = 2,
+  }
+}
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index cb31c84..facce4b 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -43,4 +43,6 @@
   boolean queryNanoapps(in int contextHubId);
   boolean registerCallback(in int contextHubId, in android.hardware.contexthub.IContextHubCallback cb);
   boolean sendMessageToHub(in int contextHubId, in android.hardware.contexthub.ContextHubMessage message);
+  void onHostEndpointConnected(in android.hardware.contexthub.HostEndpointInfo hostEndpointInfo);
+  void onHostEndpointDisconnected(char hostEndpointId);
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/HostEndpointInfo.aidl b/contexthub/aidl/android/hardware/contexthub/HostEndpointInfo.aidl
new file mode 100644
index 0000000..370703f
--- /dev/null
+++ b/contexthub/aidl/android/hardware/contexthub/HostEndpointInfo.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.contexthub;
+
+/**
+ * Stores metadata regarding a host endpoint that may communicate with the Context Hub.
+ */
+@VintfStability
+parcelable HostEndpointInfo {
+    /** The ID of the host endpoint asscociated with this host. */
+    char hostEndpointId;
+
+    /** The type of endpoint. */
+    Type type;
+
+    /** The (optional) package name of the host. */
+    @nullable String[] packageName;
+
+    /** The (optional) attribution tag associated with this host. */
+    @nullable String[] attributionTag;
+
+    @VintfStability
+    @Backing(type="int")
+    enum Type {
+        /**
+           This endpoint is from the Android framework, where packageName and attributionTag may be
+           empty.
+         */
+        TYPE_FRAMEWORK = 1,
+
+        /** This endpoint is an Android app. */
+        TYPE_APP = 2,
+    }
+}
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index e820cbf..33d241a 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.contexthub.ContextHubInfo;
 import android.hardware.contexthub.ContextHubMessage;
+import android.hardware.contexthub.HostEndpointInfo;
 import android.hardware.contexthub.IContextHubCallback;
 import android.hardware.contexthub.NanoappBinary;
 import android.hardware.contexthub.Setting;
@@ -151,4 +152,29 @@
      * @return true on success
      */
     boolean sendMessageToHub(in int contextHubId, in ContextHubMessage message);
+
+    /**
+     * Invoked when a host endpoint has connected with the ContextHubService.
+     *
+     * The host associated with this invocation may initiate a communication channel with
+     * the Context Hub using sendMessageToHub.
+     *
+     * @param hostEndpointInfo Metadata associated with this host endpoint.
+     */
+    void onHostEndpointConnected(in HostEndpointInfo hostEndpointInfo);
+
+    /**
+     * Invoked when a host endpoint has disconnected from the framework. This could be as a result
+     * of an explicit connection closure, or unexpected restarts.
+     *
+     * Note that hostEndpointId is the same as the value in HostEndpointInfo. When this function is
+     * called, the HAL is expected to clean up any resources attached to the messaging channel
+     * associated with this host endpoint ID.
+     *
+     * @param hostEndPointId The ID of the host that has disconnected.
+     *
+     * @return Status::ok on success
+     *         EX_ILLEGAL_ARGUMENT if hostEndpointId is not associated with a connected host.
+     */
+    void onHostEndpointDisconnected(char hostEndpointId);
 }
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index 1fbccc5..6da690d 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -111,6 +111,21 @@
     return ndk::ScopedAStatus::ok();
 }
 
+::ndk::ScopedAStatus ContextHub::onHostEndpointConnected(const HostEndpointInfo& in_info) {
+    mConnectedHostEndpoints.insert(in_info.hostEndpointId);
+
+    return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus ContextHub::onHostEndpointDisconnected(char16_t in_hostEndpointId) {
+    if (mConnectedHostEndpoints.count(in_hostEndpointId) > 0) {
+        mConnectedHostEndpoints.erase(in_hostEndpointId);
+        return ndk::ScopedAStatus::ok();
+    } else {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
+    }
+}
+
 }  // namespace contexthub
 }  // namespace hardware
 }  // namespace android
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index 0dbb61b..dd739e6 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -18,6 +18,8 @@
 
 #include <aidl/android/hardware/contexthub/BnContextHub.h>
 
+#include <unordered_set>
+
 namespace aidl {
 namespace android {
 namespace hardware {
@@ -41,10 +43,15 @@
     ::ndk::ScopedAStatus sendMessageToHub(int32_t in_contextHubId,
                                           const ContextHubMessage& in_message,
                                           bool* _aidl_return) override;
+    ::ndk::ScopedAStatus onHostEndpointConnected(const HostEndpointInfo& in_info) override;
+
+    ::ndk::ScopedAStatus onHostEndpointDisconnected(char16_t in_hostEndpointId) override;
 
   private:
     static constexpr uint32_t kMockHubId = 0;
     std::shared_ptr<IContextHubCallback> mCallback;
+
+    std::unordered_set<char16_t> mConnectedHostEndpoints;
 };
 
 }  // namespace contexthub
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index 4b0d60f..1b2dc29 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -36,6 +36,7 @@
 using ::android::hardware::contexthub::AsyncEventType;
 using ::android::hardware::contexthub::ContextHubInfo;
 using ::android::hardware::contexthub::ContextHubMessage;
+using ::android::hardware::contexthub::HostEndpointInfo;
 using ::android::hardware::contexthub::IContextHub;
 using ::android::hardware::contexthub::IContextHubCallbackDefault;
 using ::android::hardware::contexthub::NanoappBinary;
@@ -330,6 +331,22 @@
     return tuples;
 }
 
+TEST_P(ContextHubAidl, TestHostConnection) {
+    constexpr char16_t kHostEndpointId = 1;
+    HostEndpointInfo hostEndpointInfo;
+    hostEndpointInfo.hostEndpointId = kHostEndpointId;
+
+    ASSERT_TRUE(contextHub->onHostEndpointConnected(hostEndpointInfo).isOk());
+    ASSERT_TRUE(contextHub->onHostEndpointDisconnected(kHostEndpointId).isOk());
+}
+
+TEST_P(ContextHubAidl, TestInvalidHostConnection) {
+    constexpr char16_t kHostEndpointId = 1;
+
+    Status status = contextHub->onHostEndpointDisconnected(kHostEndpointId);
+    ASSERT_EQ(status.exceptionCode(), android::binder::Status::EX_ILLEGAL_ARGUMENT);
+}
+
 std::string PrintGeneratedTest(const testing::TestParamInfo<ContextHubAidl::ParamType>& info) {
     return std::string("CONTEXT_HUB_ID_") + std::to_string(std::get<1>(info.param));
 }