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