Merge "Add nfc aidl service"
diff --git a/guest/hals/nfc/Android.bp b/guest/hals/nfc/Android.bp
new file mode 100644
index 0000000..9d9c3b4
--- /dev/null
+++ b/guest/hals/nfc/Android.bp
@@ -0,0 +1,26 @@
+cc_binary {
+    name: "android.hardware.nfc-service.cuttlefish",
+    relative_install_path: "hw",
+    init_rc: ["nfc-service-cuttlefish.rc"],
+    vintf_fragments: ["nfc-service-cuttlefish.xml"],
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+        "libutils",
+        "libbinder_ndk",
+        "android.hardware.nfc-V1-ndk",
+    ],
+    required: [
+        "libnfc-hal-cf.conf-default",
+    ],
+    srcs: [
+        "main.cc",
+        "Nfc.cc",
+        "Cf_hal_api.cc",
+    ],
+}
diff --git a/guest/hals/nfc/Cf_hal_api.cc b/guest/hals/nfc/Cf_hal_api.cc
new file mode 100644
index 0000000..ed564d2
--- /dev/null
+++ b/guest/hals/nfc/Cf_hal_api.cc
@@ -0,0 +1,346 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <string.h>
+
+#include "Cf_hal_api.h"
+#include "hardware_nfc.h"
+
+using android::base::StringPrintf;
+
+bool hal_opened = false;
+bool dbg_logging = false;
+pthread_mutex_t hmutex = PTHREAD_MUTEX_INITIALIZER;
+nfc_stack_callback_t* e_cback;
+nfc_stack_data_callback_t* d_cback;
+
+static struct aidl_callback_struct {
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+  pthread_t thr;
+  int event_pending;
+  int stop_thread;
+  int thread_running;
+  nfc_event_t event;
+  nfc_status_t event_status;
+} aidl_callback_data;
+
+static void* aidl_callback_thread_fct(void* arg) {
+  int ret;
+  struct aidl_callback_struct* pcb_data = (struct aidl_callback_struct*)arg;
+
+  ret = pthread_mutex_lock(&pcb_data->mutex);
+  if (ret != 0) {
+    LOG(ERROR) << StringPrintf("%s pthread_mutex_lock failed", __func__);
+    goto error;
+  }
+
+  do {
+    if (pcb_data->event_pending == 0) {
+      ret = pthread_cond_wait(&pcb_data->cond, &pcb_data->mutex);
+      if (ret != 0) {
+        LOG(ERROR) << StringPrintf("%s pthread_cond_wait failed", __func__);
+        break;
+      }
+    }
+
+    if (pcb_data->event_pending) {
+      nfc_event_t event = pcb_data->event;
+      nfc_status_t event_status = pcb_data->event_status;
+      int ending = pcb_data->stop_thread;
+      pcb_data->event_pending = 0;
+      ret = pthread_cond_signal(&pcb_data->cond);
+      if (ret != 0) {
+        LOG(ERROR) << StringPrintf("%s pthread_cond_signal failed", __func__);
+        break;
+      }
+      if (ending) {
+        pcb_data->thread_running = 0;
+      }
+      ret = pthread_mutex_unlock(&pcb_data->mutex);
+      if (ret != 0) {
+        LOG(ERROR) << StringPrintf("%s pthread_mutex_unlock failed", __func__);
+      }
+      LOG(INFO) << StringPrintf("%s event %hhx status %hhx", __func__, event,
+                                event_status);
+      e_cback(event, event_status);
+      usleep(50000);
+      if (ending) {
+        return NULL;
+      }
+      ret = pthread_mutex_lock(&pcb_data->mutex);
+      if (ret != 0) {
+        LOG(ERROR) << StringPrintf("%s pthread_mutex_lock failed", __func__);
+        goto error;
+      }
+    }
+  } while (pcb_data->stop_thread == 0 || pcb_data->event_pending);
+
+  ret = pthread_mutex_unlock(&pcb_data->mutex);
+  if (ret != 0) {
+    LOG(ERROR) << StringPrintf("%s pthread_mutex_unlock failed", __func__);
+  }
+
+error:
+  pcb_data->thread_running = 0;
+  return NULL;
+}
+
+static int aidl_callback_thread_start() {
+  int ret;
+  LOG(INFO) << StringPrintf("%s", __func__);
+
+  memset(&aidl_callback_data, 0, sizeof(aidl_callback_data));
+
+  ret = pthread_mutex_init(&aidl_callback_data.mutex, NULL);
+  if (ret != 0) {
+    LOG(ERROR) << StringPrintf("%s pthread_mutex_init failed", __func__);
+    return ret;
+  }
+
+  ret = pthread_cond_init(&aidl_callback_data.cond, NULL);
+  if (ret != 0) {
+    LOG(ERROR) << StringPrintf("%s pthread_cond_init failed", __func__);
+    return ret;
+  }
+
+  aidl_callback_data.thread_running = 1;
+
+  ret = pthread_create(&aidl_callback_data.thr, NULL, aidl_callback_thread_fct,
+                       &aidl_callback_data);
+  if (ret != 0) {
+    LOG(ERROR) << StringPrintf("%s pthread_create failed", __func__);
+    aidl_callback_data.thread_running = 0;
+    return ret;
+  }
+
+  return 0;
+}
+
+static int aidl_callback_thread_end() {
+  LOG(INFO) << StringPrintf("%s", __func__);
+  if (aidl_callback_data.thread_running != 0) {
+    int ret;
+
+    ret = pthread_mutex_lock(&aidl_callback_data.mutex);
+    if (ret != 0) {
+      LOG(ERROR) << StringPrintf("%s pthread_mutex_lock failed", __func__);
+      return ret;
+    }
+
+    aidl_callback_data.stop_thread = 1;
+
+    // Wait for the thread to have no event pending
+    while (aidl_callback_data.thread_running &&
+           aidl_callback_data.event_pending) {
+      ret = pthread_cond_signal(&aidl_callback_data.cond);
+      if (ret != 0) {
+        LOG(ERROR) << StringPrintf("%s pthread_cond_signal failed", __func__);
+        return ret;
+      }
+      ret = pthread_cond_wait(&aidl_callback_data.cond,
+                              &aidl_callback_data.mutex);
+      if (ret != 0) {
+        LOG(ERROR) << StringPrintf("%s pthread_cond_wait failed", __func__);
+        break;
+      }
+    }
+
+    ret = pthread_mutex_unlock(&aidl_callback_data.mutex);
+    if (ret != 0) {
+      LOG(ERROR) << StringPrintf("%s pthread_mutex_unlock failed", __func__);
+      return ret;
+    }
+
+    ret = pthread_cond_signal(&aidl_callback_data.cond);
+    if (ret != 0) {
+      LOG(ERROR) << StringPrintf("%s pthread_cond_signal failed", __func__);
+      return ret;
+    }
+
+    ret = pthread_detach(aidl_callback_data.thr);
+    if (ret != 0) {
+      LOG(ERROR) << StringPrintf("%s pthread_detach failed", __func__);
+      return ret;
+    }
+  }
+  return 0;
+}
+
+static void aidl_callback_post(nfc_event_t event, nfc_status_t event_status) {
+  int ret;
+
+  if (pthread_equal(pthread_self(), aidl_callback_data.thr)) {
+    e_cback(event, event_status);
+  }
+
+  ret = pthread_mutex_lock(&aidl_callback_data.mutex);
+  if (ret != 0) {
+    LOG(ERROR) << StringPrintf("%s pthread_mutex_lock failed", __func__);
+    return;
+  }
+
+  if (aidl_callback_data.thread_running == 0) {
+    (void)pthread_mutex_unlock(&aidl_callback_data.mutex);
+    LOG(ERROR) << StringPrintf("%s thread is not running", __func__);
+    e_cback(event, event_status);
+    return;
+  }
+
+  while (aidl_callback_data.event_pending) {
+    ret =
+        pthread_cond_wait(&aidl_callback_data.cond, &aidl_callback_data.mutex);
+    if (ret != 0) {
+      LOG(ERROR) << StringPrintf("%s pthread_cond_wait failed", __func__);
+      return;
+    }
+  }
+
+  aidl_callback_data.event_pending = 1;
+  aidl_callback_data.event = event;
+  aidl_callback_data.event_status = event_status;
+
+  ret = pthread_mutex_unlock(&aidl_callback_data.mutex);
+  if (ret != 0) {
+    LOG(ERROR) << StringPrintf("%s pthread_mutex_unlock failed", __func__);
+    return;
+  }
+
+  ret = pthread_cond_signal(&aidl_callback_data.cond);
+  if (ret != 0) {
+    LOG(ERROR) << StringPrintf("%s pthread_cond_signal failed", __func__);
+    return;
+  }
+}
+
+int Cf_hal_open(nfc_stack_callback_t* p_cback,
+                nfc_stack_data_callback_t* p_data_cback) {
+  LOG(INFO) << StringPrintf("%s", __func__);
+  pthread_mutex_lock(&hmutex);
+  if (hal_opened) {
+    // already opened, close then open again
+    LOG(INFO) << StringPrintf("%s close and open again", __func__);
+    if (aidl_callback_data.thread_running && aidl_callback_thread_end() != 0) {
+      pthread_mutex_unlock(&hmutex);
+      return -1;
+    }
+    hal_opened = false;
+  }
+  e_cback = p_cback;
+  d_cback = p_data_cback;
+  if ((hal_opened || !aidl_callback_data.thread_running) &&
+      (aidl_callback_thread_start() != 0)) {
+    // status failed
+    LOG(INFO) << StringPrintf("%s failed", __func__);
+    aidl_callback_post(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_FAILED);
+    pthread_mutex_unlock(&hmutex);
+    return -1;
+  }
+  hal_opened = true;
+  aidl_callback_post(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_OK);
+  pthread_mutex_unlock(&hmutex);
+  return 0;
+}
+
+int Cf_hal_write(uint16_t data_len, const uint8_t* p_data) {
+  if (!hal_opened) return -1;
+  // TODO: write NCI state machine
+  (void)data_len;
+  (void)p_data;
+  return 0;
+}
+
+int Cf_hal_core_initialized() {
+  if (!hal_opened) return -1;
+  pthread_mutex_lock(&hmutex);
+  aidl_callback_post(HAL_NFC_POST_INIT_CPLT_EVT, HAL_NFC_STATUS_OK);
+  pthread_mutex_unlock(&hmutex);
+  return 0;
+}
+
+int Cf_hal_pre_discover() {
+  if (!hal_opened) return -1;
+  pthread_mutex_lock(&hmutex);
+  aidl_callback_post(HAL_NFC_PRE_DISCOVER_CPLT_EVT, HAL_NFC_STATUS_OK);
+  pthread_mutex_unlock(&hmutex);
+  return 0;
+}
+
+int Cf_hal_close() {
+  LOG(INFO) << StringPrintf("%s", __func__);
+  if (!hal_opened) return -1;
+  pthread_mutex_lock(&hmutex);
+  hal_opened = false;
+  aidl_callback_post(HAL_NFC_CLOSE_CPLT_EVT, HAL_NFC_STATUS_OK);
+  if (aidl_callback_data.thread_running && aidl_callback_thread_end() != 0) {
+    LOG(ERROR) << StringPrintf("%s thread end failed", __func__);
+    pthread_mutex_unlock(&hmutex);
+    return -1;
+  }
+  pthread_mutex_unlock(&hmutex);
+  return 0;
+}
+
+int Cf_hal_close_off() {
+  LOG(INFO) << StringPrintf("%s", __func__);
+  if (!hal_opened) return -1;
+  pthread_mutex_lock(&hmutex);
+  hal_opened = false;
+  aidl_callback_post(HAL_NFC_CLOSE_CPLT_EVT, HAL_NFC_STATUS_OK);
+  if (aidl_callback_data.thread_running && aidl_callback_thread_end() != 0) {
+    LOG(ERROR) << StringPrintf("%s thread end failed", __func__);
+    pthread_mutex_unlock(&hmutex);
+    return -1;
+  }
+  pthread_mutex_unlock(&hmutex);
+  return 0;
+}
+
+int Cf_hal_power_cycle() {
+  if (!hal_opened) return -1;
+  pthread_mutex_lock(&hmutex);
+  aidl_callback_post(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_OK);
+  pthread_mutex_unlock(&hmutex);
+  return 0;
+}
+
+void Cf_hal_factoryReset() {}
+void Cf_hal_getConfig(NfcConfig& config) {
+  // TODO: read config from /vendor/etc/libnfc-hal-cf.conf
+  memset(&config, 0x00, sizeof(NfcConfig));
+  config.nfaPollBailOutMode = 1;
+  config.maxIsoDepTransceiveLength = 0xFEFF;
+  config.defaultOffHostRoute = 0x81;
+  config.defaultOffHostRouteFelica = 0x81;
+  config.defaultSystemCodeRoute = 0x00;
+  config.defaultSystemCodePowerState = 0x3B;
+  config.defaultRoute = 0x00;
+  config.offHostRouteUicc.resize(1);
+  config.offHostRouteUicc[0] = 0x81;
+  config.offHostRouteEse.resize(1);
+  config.offHostRouteEse[0] = 0x81;
+  config.defaultIsoDepRoute = 0x81;
+}
+
+void Cf_hal_setVerboseLogging(bool enable) { dbg_logging = enable; }
+
+bool Cf_hal_getVerboseLogging() { return dbg_logging; }
diff --git a/guest/hals/nfc/Cf_hal_api.h b/guest/hals/nfc/Cf_hal_api.h
new file mode 100644
index 0000000..519e853
--- /dev/null
+++ b/guest/hals/nfc/Cf_hal_api.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#ifndef _VENDOR_HAL_API_H_
+#define _VENDOR_HAL_API_H_
+
+#include <aidl/android/hardware/nfc/INfc.h>
+#include <aidl/android/hardware/nfc/NfcConfig.h>
+#include <aidl/android/hardware/nfc/NfcEvent.h>
+#include <aidl/android/hardware/nfc/NfcStatus.h>
+#include <aidl/android/hardware/nfc/PresenceCheckAlgorithm.h>
+#include <aidl/android/hardware/nfc/ProtocolDiscoveryConfig.h>
+#include "hardware_nfc.h"
+
+using aidl::android::hardware::nfc::NfcConfig;
+using aidl::android::hardware::nfc::NfcEvent;
+using aidl::android::hardware::nfc::NfcStatus;
+using aidl::android::hardware::nfc::PresenceCheckAlgorithm;
+using aidl::android::hardware::nfc::ProtocolDiscoveryConfig;
+
+int Cf_hal_open(nfc_stack_callback_t* p_cback,
+                nfc_stack_data_callback_t* p_data_cback);
+int Cf_hal_write(uint16_t data_len, const uint8_t* p_data);
+
+int Cf_hal_core_initialized();
+
+int Cf_hal_pre_discover();
+
+int Cf_hal_close();
+
+int Cf_hal_close_off();
+
+int Cf_hal_power_cycle();
+
+void Cf_hal_factoryReset();
+
+void Cf_hal_getConfig(NfcConfig& config);
+
+void Cf_hal_setVerboseLogging(bool enable);
+
+bool Cf_hal_getVerboseLogging();
+
+#endif /* _VENDOR_HAL_API_H_ */
diff --git a/guest/hals/nfc/Nfc.cc b/guest/hals/nfc/Nfc.cc
new file mode 100644
index 0000000..993d80b
--- /dev/null
+++ b/guest/hals/nfc/Nfc.cc
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#include "Nfc.h"
+
+#include <android-base/logging.h>
+
+#include "Cf_hal_api.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace nfc {
+
+std::shared_ptr<INfcClientCallback> Nfc::mCallback = nullptr;
+AIBinder_DeathRecipient* clientDeathRecipient = nullptr;
+
+void OnDeath(void* cookie) {
+  if (Nfc::mCallback != nullptr &&
+      !AIBinder_isAlive(Nfc::mCallback->asBinder().get())) {
+    LOG(INFO) << __func__ << " Nfc service has died";
+    Nfc* nfc = static_cast<Nfc*>(cookie);
+    nfc->close(NfcCloseType::DISABLE);
+  }
+}
+
+::ndk::ScopedAStatus Nfc::open(
+    const std::shared_ptr<INfcClientCallback>& clientCallback) {
+  LOG(INFO) << "open";
+  if (clientCallback == nullptr) {
+    LOG(INFO) << "Nfc::open null callback";
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(NfcStatus::FAILED));
+  } else {
+    Nfc::mCallback = clientCallback;
+
+    if (clientDeathRecipient != nullptr) {
+      AIBinder_DeathRecipient_delete(clientDeathRecipient);
+      clientDeathRecipient = nullptr;
+    }
+    clientDeathRecipient = AIBinder_DeathRecipient_new(OnDeath);
+    auto linkRet =
+        AIBinder_linkToDeath(clientCallback->asBinder().get(),
+                             clientDeathRecipient, this /* cookie */);
+    if (linkRet != STATUS_OK) {
+      LOG(ERROR) << __func__ << ": linkToDeath failed: " << linkRet;
+      // Just ignore the error.
+    }
+
+    int ret = Cf_hal_open(eventCallback, dataCallback);
+    return ret == 0 ? ndk::ScopedAStatus::ok()
+                    : ndk::ScopedAStatus::fromServiceSpecificError(
+                          static_cast<int32_t>(NfcStatus::FAILED));
+    return ndk::ScopedAStatus::ok();
+  }
+  return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::close(NfcCloseType type) {
+  LOG(INFO) << "close";
+  if (Nfc::mCallback == nullptr) {
+    LOG(ERROR) << __func__ << " mCallback null";
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(NfcStatus::FAILED));
+  }
+  int ret = 0;
+  if (type == NfcCloseType::HOST_SWITCHED_OFF) {
+    ret = Cf_hal_close_off();
+  } else {
+    ret = Cf_hal_close();
+  }
+  AIBinder_DeathRecipient_delete(clientDeathRecipient);
+  clientDeathRecipient = nullptr;
+  return ret == 0 ? ndk::ScopedAStatus::ok()
+                  : ndk::ScopedAStatus::fromServiceSpecificError(
+                        static_cast<int32_t>(NfcStatus::FAILED));
+}
+
+::ndk::ScopedAStatus Nfc::coreInitialized() {
+  LOG(INFO) << "coreInitialized";
+  if (Nfc::mCallback == nullptr) {
+    LOG(ERROR) << __func__ << "mCallback null";
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(NfcStatus::FAILED));
+  }
+  int ret = Cf_hal_core_initialized();
+
+  return ret == 0 ? ndk::ScopedAStatus::ok()
+                  : ndk::ScopedAStatus::fromServiceSpecificError(
+                        static_cast<int32_t>(NfcStatus::FAILED));
+}
+
+::ndk::ScopedAStatus Nfc::factoryReset() {
+  LOG(INFO) << "factoryReset";
+  Cf_hal_factoryReset();
+  return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::getConfig(NfcConfig* _aidl_return) {
+  LOG(INFO) << "getConfig";
+  NfcConfig nfcVendorConfig;
+  Cf_hal_getConfig(nfcVendorConfig);
+
+  *_aidl_return = nfcVendorConfig;
+  return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::powerCycle() {
+  LOG(INFO) << "powerCycle";
+  if (Nfc::mCallback == nullptr) {
+    LOG(ERROR) << __func__ << "mCallback null";
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(NfcStatus::FAILED));
+  }
+  return Cf_hal_power_cycle() ? ndk::ScopedAStatus::fromServiceSpecificError(
+                                    static_cast<int32_t>(NfcStatus::FAILED))
+                              : ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::preDiscover() {
+  LOG(INFO) << "preDiscover";
+  if (Nfc::mCallback == nullptr) {
+    LOG(ERROR) << __func__ << "mCallback null";
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(NfcStatus::FAILED));
+  }
+  return Cf_hal_pre_discover() ? ndk::ScopedAStatus::fromServiceSpecificError(
+                                     static_cast<int32_t>(NfcStatus::FAILED))
+                               : ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::write(const std::vector<uint8_t>& data,
+                                int32_t* _aidl_return) {
+  LOG(INFO) << "write";
+  if (Nfc::mCallback == nullptr) {
+    LOG(ERROR) << __func__ << "mCallback null";
+    return ndk::ScopedAStatus::fromServiceSpecificError(
+        static_cast<int32_t>(NfcStatus::FAILED));
+  }
+  *_aidl_return = Cf_hal_write(data.size(), &data[0]);
+  return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::setEnableVerboseLogging(bool enable) {
+  LOG(INFO) << "setVerboseLogging";
+  Cf_hal_setVerboseLogging(enable);
+  return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus Nfc::isVerboseLoggingEnabled(bool* _aidl_return) {
+  *_aidl_return = Cf_hal_getVerboseLogging();
+  return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace nfc
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/guest/hals/nfc/Nfc.h b/guest/hals/nfc/Nfc.h
new file mode 100644
index 0000000..cf473be
--- /dev/null
+++ b/guest/hals/nfc/Nfc.h
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/nfc/BnNfc.h>
+#include <aidl/android/hardware/nfc/INfcClientCallback.h>
+#include <android-base/logging.h>
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace nfc {
+
+using ::aidl::android::hardware::nfc::NfcCloseType;
+using ::aidl::android::hardware::nfc::NfcConfig;
+using ::aidl::android::hardware::nfc::NfcStatus;
+
+// Default implementation that reports no support NFC.
+struct Nfc : public BnNfc {
+ public:
+  Nfc() = default;
+
+  ::ndk::ScopedAStatus open(
+      const std::shared_ptr<INfcClientCallback>& clientCallback) override;
+  ::ndk::ScopedAStatus close(NfcCloseType type) override;
+  ::ndk::ScopedAStatus coreInitialized() override;
+  ::ndk::ScopedAStatus factoryReset() override;
+  ::ndk::ScopedAStatus getConfig(NfcConfig* _aidl_return) override;
+  ::ndk::ScopedAStatus powerCycle() override;
+  ::ndk::ScopedAStatus preDiscover() override;
+  ::ndk::ScopedAStatus write(const std::vector<uint8_t>& data,
+                             int32_t* _aidl_return) override;
+  ::ndk::ScopedAStatus setEnableVerboseLogging(bool enable) override;
+  ::ndk::ScopedAStatus isVerboseLoggingEnabled(bool* _aidl_return) override;
+  static void eventCallback(uint8_t event, uint8_t status) {
+    if (mCallback != nullptr) {
+      auto ret = mCallback->sendEvent((NfcEvent)event, (NfcStatus)status);
+      if (!ret.isOk()) {
+        LOG(ERROR) << "Failed to send event!";
+      }
+    }
+  }
+
+  static void dataCallback(uint16_t data_len, uint8_t* p_data) {
+    std::vector<uint8_t> data(p_data, p_data + data_len);
+    if (mCallback != nullptr) {
+      auto ret = mCallback->sendData(data);
+      if (!ret.isOk()) {
+        LOG(ERROR) << "Failed to send data!";
+      }
+    }
+  }
+  static std::shared_ptr<INfcClientCallback> mCallback;
+};
+
+}  // namespace nfc
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/guest/hals/nfc/OWNERS b/guest/hals/nfc/OWNERS
new file mode 100644
index 0000000..2c46507
--- /dev/null
+++ b/guest/hals/nfc/OWNERS
@@ -0,0 +1 @@
+include platform/packages/apps/Nfc:/OWNERS
diff --git a/guest/hals/nfc/conf/Android.bp b/guest/hals/nfc/conf/Android.bp
new file mode 100644
index 0000000..6cf234b
--- /dev/null
+++ b/guest/hals/nfc/conf/Android.bp
@@ -0,0 +1,8 @@
+prebuilt_etc {
+    name: "libnfc-hal-cf.conf-default",
+    src: "libnfc-hal-cf.conf",
+    proprietary: true,
+    vendor: true,
+    filename: "libnfc-hal-cf.conf",
+
+}
diff --git a/guest/hals/nfc/conf/libnfc-hal-cf.conf b/guest/hals/nfc/conf/libnfc-hal-cf.conf
new file mode 100644
index 0000000..e79651e
--- /dev/null
+++ b/guest/hals/nfc/conf/libnfc-hal-cf.conf
@@ -0,0 +1,120 @@
+########################### Start of libnf-hal-cf.conf ###########################
+
+###############################################################################
+###############################################################################
+# CF HAL trace log level
+CFNFC_HAL_LOGLEVEL=4
+NFC_DEBUG_ENABLED=0
+
+###############################################################################
+# File used for NFA storage
+NFA_STORAGE="/data/nfc"
+
+###############################################################################
+# Keep the nfa storage file.
+PRESERVE_STORAGE=1
+
+###############################################################################
+# Vendor Specific Proprietary Protocol & Discovery Configuration
+# Set to 0xFF if unsupported
+#  byte[0] NCI_PROTOCOL_18092_ACTIVE
+#  byte[1] NCI_PROTOCOL_B_PRIME
+#  byte[2] NCI_PROTOCOL_DUAL
+#  byte[3] NCI_PROTOCOL_15693
+#  byte[4] NCI_PROTOCOL_KOVIO
+#  byte[5] NCI_PROTOCOL_MIFARE
+#  byte[6] NCI_DISCOVERY_TYPE_POLL_KOVIO
+#  byte[7] NCI_DISCOVERY_TYPE_POLL_B_PRIME
+#  byte[8] NCI_DISCOVERY_TYPE_LISTEN_B_PRIME
+NFA_PROPRIETARY_CFG={05:FF:FF:06:8A:90:77:FF:FF}
+
+###############################################################################
+# Choose the presence-check algorithm for type-4 tag.  If not defined,
+# the default value is 1.
+# 0  NFA_RW_PRES_CHK_DEFAULT; Let stack selects an algorithm
+# 1  NFA_RW_PRES_CHK_I_BLOCK; ISO-DEP protocol's empty I-block
+# 2  NFA_RW_PRES_CHK_RESET; Deactivate to Sleep, then re-activate
+# 3  NFA_RW_PRES_CHK_RB_CH0; Type-4 tag protocol's ReadBinary command on channel 0
+# 4  NFA_RW_PRES_CHK_RB_CH3; Type-4 tag protocol's ReadBinary command on channel 3
+# 5  NFA_RW_PRES_CHK_ISO_DEP_NAK; presence check command ISO-DEP NAK as per NCI2.0
+PRESENCE_CHECK_ALGORITHM=5
+
+###############################################################################
+# Name of the NCI HAL module to use
+# If unset, falls back to nfc_nci.bcm2079x
+NCI_HAL_MODULE="nfc_nci.st21nfc"
+
+###############################################################################
+# White list to be set at startup.
+DEVICE_HOST_ALLOW_LIST={02:C0}
+
+###############################################################################
+# BAIL OUT value for P2P
+# Implements algorithm for NFC-DEP protocol priority over ISO-DEP protocol.
+POLL_BAIL_OUT_MODE=1
+
+###############################################################################
+# Extended APDU length for ISO_DEP
+ISO_DEP_MAX_TRANSCEIVE=0xFEFF
+
+###############################################################################
+# Configure the NFC Extras to open and use a static pipe.  If the value is
+# not set or set to 0, then the default is use a dynamic pipe based on a
+# destination gate (see NFA_HCI_DEFAULT_DEST_GATE).  Note there is a value
+# for each EE (ESE/SIM)
+OFF_HOST_ESE_PIPE_ID=0x5E
+OFF_HOST_SIM_PIPE_ID=0x3E
+
+###############################################################################
+#Set the default Felica T3T System Code OffHost route Location :
+#This settings will be used when application does not set this parameter
+# host  0x00
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+DEFAULT_SYS_CODE_ROUTE=0x86
+
+###############################################################################
+#Set the Felica T3T System Code supported power state:
+DEFAULT_SYS_CODE_PWR_STATE=0x3B
+
+###############################################################################
+# Default off-host route for Felica.
+# This settings will be used when application does not set this parameter
+# host  0x00
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+DEFAULT_NFCF_ROUTE=0x86
+
+###############################################################################
+# Configure the default off-host route.
+# used for technology A and B routing
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+DEFAULT_OFFHOST_ROUTE=0x81
+
+###############################################################################
+# Configure the default AID route.
+# host  0x00
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+DEFAULT_ROUTE=0x00
+
+###############################################################################
+# Configure the NFCEEIDs of offhost UICC.
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+OFFHOST_ROUTE_UICC={81}
+
+###############################################################################
+# Configure the NFCEEIDs of offhost eSEs.
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+OFFHOST_ROUTE_ESE={86}
+
+###############################################################################
+# Configure the list of NFCEE for the ISO-DEP routing.
+# host  0x00
+# eSE   0x82 (eSE),    0x86 (eUICC/SPI-SE)
+# UICC  0x81 (UICC_1), 0x85 (UICC_2)
+DEFAULT_ISODEP_ROUTE=0x81
+
+
+
diff --git a/guest/hals/nfc/hardware_nfc.h b/guest/hals/nfc/hardware_nfc.h
new file mode 100644
index 0000000..b266541
--- /dev/null
+++ b/guest/hals/nfc/hardware_nfc.h
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+#pragma once
+
+typedef uint8_t nfc_event_t;
+typedef uint8_t nfc_status_t;
+
+/*
+ * The callback passed in from the NFC stack that the HAL
+ * can use to pass events back to the stack.
+ */
+typedef void(nfc_stack_callback_t)(nfc_event_t event,
+                                   nfc_status_t event_status);
+
+/*
+ * The callback passed in from the NFC stack that the HAL
+ * can use to pass incomming data to the stack.
+ */
+typedef void(nfc_stack_data_callback_t)(uint16_t data_len, uint8_t* p_data);
+
+enum {
+  HAL_NFC_OPEN_CPLT_EVT = 0u,
+  HAL_NFC_CLOSE_CPLT_EVT = 1u,
+  HAL_NFC_POST_INIT_CPLT_EVT = 2u,
+  HAL_NFC_PRE_DISCOVER_CPLT_EVT = 3u,
+  HAL_NFC_REQUEST_CONTROL_EVT = 4u,
+  HAL_NFC_RELEASE_CONTROL_EVT = 5u,
+  HAL_NFC_ERROR_EVT = 6u,
+  HAL_HCI_NETWORK_RESET = 7u,
+};
+
+enum {
+  HAL_NFC_STATUS_OK = 0u,
+  HAL_NFC_STATUS_FAILED = 1u,
+  HAL_NFC_STATUS_ERR_TRANSPORT = 2u,
+  HAL_NFC_STATUS_ERR_CMD_TIMEOUT = 3u,
+  HAL_NFC_STATUS_REFUSED = 4u,
+};
diff --git a/guest/hals/nfc/main.cc b/guest/hals/nfc/main.cc
new file mode 100644
index 0000000..51ec8ce
--- /dev/null
+++ b/guest/hals/nfc/main.cc
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "Nfc.h"
+using ::aidl::android::hardware::nfc::Nfc;
+
+int main() {
+  LOG(INFO) << "NFC HAL starting up";
+  if (!ABinderProcess_setThreadPoolMaxThreadCount(1)) {
+    LOG(INFO) << "failed to set thread pool max thread count";
+    return 1;
+  }
+  std::shared_ptr<Nfc> nfc_service = ndk::SharedRefBase::make<Nfc>();
+
+  const std::string instance = std::string() + Nfc::descriptor + "/default";
+  CHECK_EQ(STATUS_OK, AServiceManager_addService(nfc_service->asBinder().get(),
+                                                 instance.c_str()));
+  ABinderProcess_joinThreadPool();
+  return 0;
+}
diff --git a/guest/hals/nfc/nfc-service-cuttlefish.rc b/guest/hals/nfc/nfc-service-cuttlefish.rc
new file mode 100644
index 0000000..e8f6505
--- /dev/null
+++ b/guest/hals/nfc/nfc-service-cuttlefish.rc
@@ -0,0 +1,4 @@
+service nfc_hal_service /vendor/bin/hw/android.hardware.nfc-service.cuttlefish
+    class hal
+    user nfc
+    group nfc
diff --git a/guest/hals/nfc/nfc-service-cuttlefish.xml b/guest/hals/nfc/nfc-service-cuttlefish.xml
new file mode 100644
index 0000000..70fed20
--- /dev/null
+++ b/guest/hals/nfc/nfc-service-cuttlefish.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.nfc</name>
+        <fqname>INfc/default</fqname>
+    </hal>
+</manifest>
diff --git a/shared/device.mk b/shared/device.mk
index bf97925..d35227d 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -792,3 +792,7 @@
 # Vendor Dlkm Locader
 PRODUCT_PACKAGES += \
    dlkm_loader
+
+# NFC AIDL HAL
+PRODUCT_PACKAGES += \
+    android.hardware.nfc-service.cuttlefish
diff --git a/shared/sepolicy/vendor/file_contexts b/shared/sepolicy/vendor/file_contexts
index f6903b7..69ed74f 100644
--- a/shared/sepolicy/vendor/file_contexts
+++ b/shared/sepolicy/vendor/file_contexts
@@ -79,6 +79,7 @@
 /vendor/bin/hw/android\.hardware\.neuralnetworks@1\.3-service-sample-.*   u:object_r:hal_neuralnetworks_sample_exec:s0
 /vendor/bin/hw/android\.hardware\.neuralnetworks-shim-service-sample   u:object_r:hal_neuralnetworks_sample_exec:s0
 /vendor/bin/hw/android\.hardware\.neuralnetworks-service-sample-.*   u:object_r:hal_neuralnetworks_sample_exec:s0
+/vendor/bin/hw/android\.hardware\.nfc-service\.cuttlefish  u:object_r:hal_nfc_default_exec:s0
 /vendor/bin/hw/android\.hardware\.vibrator@1\.x-service\.example u:object_r:hal_vibrator_default_exec:s0
 /vendor/bin/setup_wifi  u:object_r:setup_wifi_exec:s0
 /vendor/bin/bt_vhci_forwarder  u:object_r:bt_vhci_forwarder_exec:s0