summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBadhri Jagan Sridharan <badhri@google.com>2022-01-31 22:15:15 -0800
committerBadhri Jagan Sridharan <badhri@google.com>2022-05-09 21:51:05 -0700
commitadf891674519dcfce4abaab639085250cedc5bad (patch)
tree5681ad1085e83cdc152ec6454964f1f6503a6d43
parent7c056e2897b36445bee066d03083f7cafb34a338 (diff)
downloadredfin-adf891674519dcfce4abaab639085250cedc5bad.tar.gz
Migrate IUsb implementation to AIDL
This change migrates IUsb implementation to AIDL. Also, IUsb and IUsbGadget now run in its own processes to improve stability and isolation. Port of 3c97a6bb68f6418ee41026f3bd0024405c97cf0c Bug: 200993386 Change-Id: I681c1ba9c4f547e3cf5dc0fa7c9ee1aaf4fd603c
-rw-r--r--device-redfin.mk5
-rw-r--r--usb/Usb.cpp840
-rw-r--r--usb/Usb.h103
-rw-r--r--usb/gadget/Android.bp (renamed from usb/Android.bp)13
-rw-r--r--usb/gadget/UsbGadget.cpp (renamed from usb/UsbGadget.cpp)0
-rw-r--r--usb/gadget/UsbGadget.h (renamed from usb/UsbGadget.h)0
-rw-r--r--usb/gadget/android.hardware.usb.gadget-service.redfin.rc (renamed from usb/android.hardware.usb@1.3-service.redfin.rc)2
-rw-r--r--usb/gadget/android.hardware.usb.gadget@1.1-service.redfin.xml (renamed from usb/android.hardware.usb.gadget@1.1-service.redfin.xml)0
-rw-r--r--usb/gadget/service_gadget.cpp (renamed from usb/service.cpp)22
-rw-r--r--usb/usb/Android.bp50
-rw-r--r--usb/usb/Usb.cpp835
-rw-r--r--usb/usb/Usb.h90
-rw-r--r--usb/usb/android.hardware.usb-service.rc4
-rw-r--r--usb/usb/android.hardware.usb-service.xml (renamed from usb/android.hardware.usb@1.3-service.redfin.xml)6
-rw-r--r--usb/usb/service.cpp37
15 files changed, 1032 insertions, 975 deletions
diff --git a/device-redfin.mk b/device-redfin.mk
index fc6f260..fa45916 100644
--- a/device-redfin.mk
+++ b/device-redfin.mk
@@ -130,8 +130,11 @@ ifeq ($(wildcard vendor/google_devices/redfin/proprietary/device-vendor-redfin.m
BUILD_WITHOUT_VENDOR := true
endif
+# USB HAL
PRODUCT_PACKAGES += \
- android.hardware.usb@1.3-service.redfin
+ android.hardware.usb-service.redfin
+PRODUCT_PACKAGES += \
+ android.hardware.usb.gadget-service.redfin
# Vibrator HAL
PRODUCT_PACKAGES += \
diff --git a/usb/Usb.cpp b/usb/Usb.cpp
deleted file mode 100644
index dde01ce..0000000
--- a/usb/Usb.cpp
+++ /dev/null
@@ -1,840 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "android.hardware.usb@1.3-service.redfin"
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <assert.h>
-#include <dirent.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <chrono>
-#include <regex>
-#include <thread>
-#include <unordered_map>
-
-#include <cutils/uevent.h>
-#include <sys/epoll.h>
-#include <utils/Errors.h>
-#include <utils/StrongPointer.h>
-
-#include "Usb.h"
-
-using android::base::GetProperty;
-
-namespace android {
-namespace hardware {
-namespace usb {
-namespace V1_3 {
-namespace implementation {
-
-Return<bool> Usb::enableUsbDataSignal(bool enable) {
- bool result = true;
-
- ALOGI("Userspace turn %s USB data signaling", enable ? "on" : "off");
-
- if (enable) {
- if (!WriteStringToFile("1", USB_DATA_PATH)) {
- ALOGE("Not able to turn on usb connection notification");
- result = false;
- }
-
- if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
- ALOGE("Gadget cannot be pulled up");
- result = false;
- }
- } else {
- if (!WriteStringToFile("1", ID_PATH)) {
- ALOGE("Not able to turn off host mode");
- result = false;
- }
-
- if (!WriteStringToFile("0", VBUS_PATH)) {
- ALOGE("Not able to set Vbus state");
- result = false;
- }
-
- if (!WriteStringToFile("0", USB_DATA_PATH)) {
- ALOGE("Not able to turn on usb connection notification");
- result = false;
- }
-
- if (!WriteStringToFile("none", PULLUP_PATH)) {
- ALOGE("Gadget cannot be pulled down");
- result = false;
- }
- }
-
- return result;
-}
-
-// Set by the signal handler to destroy the thread
-volatile bool destroyThread;
-
-constexpr char kEnabledPath[] = "/sys/class/power_supply/usb/moisture_detection_enabled";
-constexpr char kDetectedPath[] = "/sys/class/power_supply/usb/moisture_detected";
-constexpr char kConsole[] = "init.svc.console";
-constexpr char kDisableContatminantDetection[] = "vendor.usb.contaminantdisable";
-
-void queryVersionHelper(implementation::Usb *usb, hidl_vec<PortStatus> *currentPortStatus_1_2);
-
-int32_t readFile(const std::string &filename, std::string *contents) {
- FILE *fp;
- ssize_t read = 0;
- char *line = NULL;
- size_t len = 0;
-
- fp = fopen(filename.c_str(), "r");
- if (fp != NULL) {
- if ((read = getline(&line, &len, fp)) != -1) {
- char *pos;
- if ((pos = strchr(line, '\n')) != NULL)
- *pos = '\0';
- *contents = line;
- }
- free(line);
- fclose(fp);
- return 0;
- } else {
- ALOGE("fopen failed");
- }
-
- return -1;
-}
-
-int32_t writeFile(const std::string &filename, const std::string &contents) {
- FILE *fp;
- std::string written;
-
- fp = fopen(filename.c_str(), "w");
- if (fp != NULL) {
- // FAILURE RETRY
- int ret = fputs(contents.c_str(), fp);
- fclose(fp);
- if ((ret != EOF) && !readFile(filename, &written) && written == contents)
- return 0;
- }
- return -1;
-}
-
-Status queryMoistureDetectionStatus(hidl_vec<PortStatus> *currentPortStatus_1_2) {
- std::string enabled, status;
-
- if (currentPortStatus_1_2 == NULL || currentPortStatus_1_2->size() == 0) {
- ALOGE("currentPortStatus_1_2 is not available");
- return Status::ERROR;
- }
-
- (*currentPortStatus_1_2)[0].supportedContaminantProtectionModes = 0;
- (*currentPortStatus_1_2)[0].supportedContaminantProtectionModes |=
- V1_2::ContaminantProtectionMode::FORCE_SINK;
- (*currentPortStatus_1_2)[0].contaminantProtectionStatus = V1_2::ContaminantProtectionStatus::NONE;
- (*currentPortStatus_1_2)[0].contaminantDetectionStatus = V1_2::ContaminantDetectionStatus::DISABLED;
- (*currentPortStatus_1_2)[0].supportsEnableContaminantPresenceDetection = true;
- (*currentPortStatus_1_2)[0].supportsEnableContaminantPresenceProtection = false;
-
- if (readFile(kEnabledPath, &enabled)) {
- ALOGE("Failed to open moisture_detection_enabled");
- return Status::ERROR;
- }
-
- if (enabled == "1") {
- if (readFile(kDetectedPath, &status)) {
- ALOGE("Failed to open moisture_detected");
- return Status::ERROR;
- }
- if (status == "1") {
- (*currentPortStatus_1_2)[0].contaminantDetectionStatus =
- V1_2::ContaminantDetectionStatus::DETECTED;
- (*currentPortStatus_1_2)[0].contaminantProtectionStatus =
- V1_2::ContaminantProtectionStatus::FORCE_SINK;
- } else
- (*currentPortStatus_1_2)[0].contaminantDetectionStatus =
- V1_2::ContaminantDetectionStatus::NOT_DETECTED;
- }
-
- ALOGI("ContaminantDetectionStatus:%d ContaminantProtectionStatus:%d",
- (*currentPortStatus_1_2)[0].contaminantDetectionStatus,
- (*currentPortStatus_1_2)[0].contaminantProtectionStatus);
-
- return Status::SUCCESS;
-}
-
-Return<void> Usb::enableContaminantPresenceDetection(const hidl_string & /*portName*/,
- bool enable) {
-
- std::string status = GetProperty(kConsole, "");
- std::string disable = GetProperty(kDisableContatminantDetection, "");
-
- if (status != "running" && disable != "true")
- writeFile(kEnabledPath, enable ? "1" : "0");
-
- hidl_vec<PortStatus> currentPortStatus_1_2;
-
- queryVersionHelper(this, &currentPortStatus_1_2);
- return Void();
-}
-
-Return<void> Usb::enableContaminantPresenceProtection(const hidl_string & /*portName*/,
- bool /*enable*/) {
- hidl_vec<PortStatus> currentPortStatus_1_2;
-
- queryVersionHelper(this, &currentPortStatus_1_2);
- return Void();
-}
-
-std::string appendRoleNodeHelper(const std::string &portName, PortRoleType type) {
- std::string node("/sys/class/typec/" + portName);
-
- switch (type) {
- case PortRoleType::DATA_ROLE:
- return node + "/data_role";
- case PortRoleType::POWER_ROLE:
- return node + "/power_role";
- case PortRoleType::MODE:
- return node + "/port_type";
- default:
- return "";
- }
-}
-
-std::string convertRoletoString(PortRole role) {
- if (role.type == PortRoleType::POWER_ROLE) {
- if (role.role == static_cast<uint32_t>(PortPowerRole::SOURCE))
- return "source";
- else if (role.role == static_cast<uint32_t>(PortPowerRole::SINK))
- return "sink";
- } else if (role.type == PortRoleType::DATA_ROLE) {
- if (role.role == static_cast<uint32_t>(PortDataRole::HOST))
- return "host";
- if (role.role == static_cast<uint32_t>(PortDataRole::DEVICE))
- return "device";
- } else if (role.type == PortRoleType::MODE) {
- if (role.role == static_cast<uint32_t>(PortMode_1_1::UFP))
- return "sink";
- if (role.role == static_cast<uint32_t>(PortMode_1_1::DFP))
- return "source";
- }
- return "none";
-}
-
-void extractRole(std::string *roleName) {
- std::size_t first, last;
-
- first = roleName->find("[");
- last = roleName->find("]");
-
- if (first != std::string::npos && last != std::string::npos) {
- *roleName = roleName->substr(first + 1, last - first - 1);
- }
-}
-
-void switchToDrp(const std::string &portName) {
- std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), PortRoleType::MODE);
- FILE *fp;
-
- if (filename != "") {
- fp = fopen(filename.c_str(), "w");
- if (fp != NULL) {
- int ret = fputs("dual", fp);
- fclose(fp);
- if (ret == EOF)
- ALOGE("Fatal: Error while switching back to drp");
- } else {
- ALOGE("Fatal: Cannot open file to switch back to drp");
- }
- } else {
- ALOGE("Fatal: invalid node type");
- }
-}
-
-bool switchMode(const hidl_string &portName, const PortRole &newRole, struct Usb *usb) {
- std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
- std::string written;
- FILE *fp;
- bool roleSwitch = false;
-
- if (filename == "") {
- ALOGE("Fatal: invalid node type");
- return false;
- }
-
- fp = fopen(filename.c_str(), "w");
- if (fp != NULL) {
- // Hold the lock here to prevent loosing connected signals
- // as once the file is written the partner added signal
- // can arrive anytime.
- pthread_mutex_lock(&usb->mPartnerLock);
- usb->mPartnerUp = false;
- int ret = fputs(convertRoletoString(newRole).c_str(), fp);
- fclose(fp);
-
- if (ret != EOF) {
- struct timespec to;
- struct timespec now;
-
- wait_again:
- clock_gettime(CLOCK_MONOTONIC, &now);
- to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
- to.tv_nsec = now.tv_nsec;
-
- int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
- // There are no uevent signals which implies role swap timed out.
- if (err == ETIMEDOUT) {
- ALOGI("uevents wait timedout");
- // Sanity check.
- } else if (!usb->mPartnerUp) {
- goto wait_again;
- // Role switch succeeded since usb->mPartnerUp is true.
- } else {
- roleSwitch = true;
- }
- } else {
- ALOGI("Role switch failed while wrting to file");
- }
- pthread_mutex_unlock(&usb->mPartnerLock);
- }
-
- if (!roleSwitch)
- switchToDrp(std::string(portName.c_str()));
-
- return roleSwitch;
-}
-
-Usb::Usb()
- : mLock(PTHREAD_MUTEX_INITIALIZER),
- mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
- mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
- mPartnerUp(false) {
- pthread_condattr_t attr;
- if (pthread_condattr_init(&attr)) {
- ALOGE("pthread_condattr_init failed: %s", strerror(errno));
- abort();
- }
- if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
- ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
- abort();
- }
- if (pthread_cond_init(&mPartnerCV, &attr)) {
- ALOGE("pthread_cond_init failed: %s", strerror(errno));
- abort();
- }
- if (pthread_condattr_destroy(&attr)) {
- ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
- abort();
- }
-}
-
-Return<void> Usb::switchRole(const hidl_string &portName, const V1_0::PortRole &newRole) {
- std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
- std::string written;
- FILE *fp;
- bool roleSwitch = false;
-
- if (filename == "") {
- ALOGE("Fatal: invalid node type");
- return Void();
- }
-
- pthread_mutex_lock(&mRoleSwitchLock);
-
- ALOGI("filename write: %s role:%s", filename.c_str(), convertRoletoString(newRole).c_str());
-
- if (newRole.type == PortRoleType::MODE) {
- roleSwitch = switchMode(portName, newRole, this);
- } else {
- fp = fopen(filename.c_str(), "w");
- if (fp != NULL) {
- int ret = fputs(convertRoletoString(newRole).c_str(), fp);
- fclose(fp);
- if ((ret != EOF) && !readFile(filename, &written)) {
- extractRole(&written);
- ALOGI("written: %s", written.c_str());
- if (written == convertRoletoString(newRole)) {
- roleSwitch = true;
- } else {
- ALOGE("Role switch failed");
- }
- } else {
- ALOGE("failed to update the new role");
- }
- } else {
- ALOGE("fopen failed");
- }
- }
-
- pthread_mutex_lock(&mLock);
- if (mCallback_1_0 != NULL) {
- Return<void> ret = mCallback_1_0->notifyRoleSwitchStatus(
- portName, newRole, roleSwitch ? Status::SUCCESS : Status::ERROR);
- if (!ret.isOk())
- ALOGE("RoleSwitchStatus error %s", ret.description().c_str());
- } else {
- ALOGE("Not notifying the userspace. Callback is not set");
- }
- pthread_mutex_unlock(&mLock);
- pthread_mutex_unlock(&mRoleSwitchLock);
-
- return Void();
-}
-
-Status getAccessoryConnected(const std::string &portName, std::string *accessory) {
- std::string filename = "/sys/class/typec/" + portName + "-partner/accessory_mode";
-
- if (readFile(filename, accessory)) {
- ALOGE("getAccessoryConnected: Failed to open filesystem node: %s", filename.c_str());
- return Status::ERROR;
- }
-
- return Status::SUCCESS;
-}
-
-Status getCurrentRoleHelper(const std::string &portName, bool connected, PortRoleType type,
- uint32_t *currentRole) {
- std::string filename;
- std::string roleName;
- std::string accessory;
-
- // Mode
-
- if (type == PortRoleType::POWER_ROLE) {
- filename = "/sys/class/typec/" + portName + "/power_role";
- *currentRole = static_cast<uint32_t>(PortPowerRole::NONE);
- } else if (type == PortRoleType::DATA_ROLE) {
- filename = "/sys/class/typec/" + portName + "/data_role";
- *currentRole = static_cast<uint32_t>(PortDataRole::NONE);
- } else if (type == PortRoleType::MODE) {
- filename = "/sys/class/typec/" + portName + "/data_role";
- *currentRole = static_cast<uint32_t>(PortMode_1_1::NONE);
- } else {
- return Status::ERROR;
- }
-
- if (!connected)
- return Status::SUCCESS;
-
- if (type == PortRoleType::MODE) {
- if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
- return Status::ERROR;
- }
- if (accessory == "analog_audio") {
- *currentRole = static_cast<uint32_t>(PortMode_1_1::AUDIO_ACCESSORY);
- return Status::SUCCESS;
- } else if (accessory == "debug") {
- *currentRole = static_cast<uint32_t>(PortMode_1_1::DEBUG_ACCESSORY);
- return Status::SUCCESS;
- }
- }
-
- if (readFile(filename, &roleName)) {
- ALOGE("getCurrentRole: Failed to open filesystem node: %s", filename.c_str());
- return Status::ERROR;
- }
-
- extractRole(&roleName);
-
- if (roleName == "source") {
- *currentRole = static_cast<uint32_t>(PortPowerRole::SOURCE);
- } else if (roleName == "sink") {
- *currentRole = static_cast<uint32_t>(PortPowerRole::SINK);
- } else if (roleName == "host") {
- if (type == PortRoleType::DATA_ROLE)
- *currentRole = static_cast<uint32_t>(PortDataRole::HOST);
- else
- *currentRole = static_cast<uint32_t>(PortMode_1_1::DFP);
- } else if (roleName == "device") {
- if (type == PortRoleType::DATA_ROLE)
- *currentRole = static_cast<uint32_t>(PortDataRole::DEVICE);
- else
- *currentRole = static_cast<uint32_t>(PortMode_1_1::UFP);
- } else if (roleName != "none") {
- /* case for none has already been addressed.
- * so we check if the role isnt none.
- */
- return Status::UNRECOGNIZED_ROLE;
- }
-
- return Status::SUCCESS;
-}
-
-Status getTypeCPortNamesHelper(std::unordered_map<std::string, bool> *names) {
- DIR *dp;
-
- dp = opendir("/sys/class/typec");
- if (dp != NULL) {
- struct dirent *ep;
-
- while ((ep = readdir(dp))) {
- if (ep->d_type == DT_LNK) {
- if (std::string::npos == std::string(ep->d_name).find("-partner")) {
- std::unordered_map<std::string, bool>::const_iterator portName =
- names->find(ep->d_name);
- if (portName == names->end()) {
- names->insert({ep->d_name, false});
- }
- } else {
- (*names)[std::strtok(ep->d_name, "-")] = true;
- }
- }
- }
- closedir(dp);
- return Status::SUCCESS;
- }
-
- ALOGE("Failed to open /sys/class/typec");
- return Status::ERROR;
-}
-
-bool canSwitchRoleHelper(const std::string &portName, PortRoleType /*type*/) {
- std::string filename = "/sys/class/typec/" + portName + "-partner/supports_usb_power_delivery";
- std::string supportsPD;
-
- if (!readFile(filename, &supportsPD)) {
- if (supportsPD == "yes") {
- return true;
- }
- }
-
- return false;
-}
-
-/*
- * Reuse the same method for both V1_0 and V1_1 callback objects.
- * The caller of this method would reconstruct the V1_0::PortStatus
- * object if required.
- */
-Status getPortStatusHelper(hidl_vec<PortStatus> *currentPortStatus_1_2, HALVersion version) {
- std::unordered_map<std::string, bool> names;
- Status result = getTypeCPortNamesHelper(&names);
- int i = -1;
-
- if (result == Status::SUCCESS) {
- currentPortStatus_1_2->resize(names.size());
- for (std::pair<std::string, bool> port : names) {
- i++;
- ALOGI("%s", port.first.c_str());
- (*currentPortStatus_1_2)[i].status_1_1.status.portName = port.first;
-
- uint32_t currentRole;
- if (getCurrentRoleHelper(port.first, port.second, PortRoleType::POWER_ROLE,
- &currentRole) == Status::SUCCESS) {
- (*currentPortStatus_1_2)[i].status_1_1.status.currentPowerRole =
- static_cast<PortPowerRole>(currentRole);
- } else {
- ALOGE("Error while retreiving portNames");
- goto done;
- }
-
- if (getCurrentRoleHelper(port.first, port.second, PortRoleType::DATA_ROLE,
- &currentRole) == Status::SUCCESS) {
- (*currentPortStatus_1_2)[i].status_1_1.status.currentDataRole =
- static_cast<PortDataRole>(currentRole);
- } else {
- ALOGE("Error while retreiving current port role");
- goto done;
- }
-
- if (getCurrentRoleHelper(port.first, port.second, PortRoleType::MODE, &currentRole) ==
- Status::SUCCESS) {
- (*currentPortStatus_1_2)[i].status_1_1.currentMode =
- static_cast<PortMode_1_1>(currentRole);
- (*currentPortStatus_1_2)[i].status_1_1.status.currentMode =
- static_cast<V1_0::PortMode>(currentRole);
- } else {
- ALOGE("Error while retreiving current data role");
- goto done;
- }
-
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangeMode = true;
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangeDataRole =
- port.second ? canSwitchRoleHelper(port.first, PortRoleType::DATA_ROLE) : false;
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangePowerRole =
- port.second ? canSwitchRoleHelper(port.first, PortRoleType::POWER_ROLE) : false;
-
- if (version == HALVersion::V1_0) {
- ALOGI("HAL version V1_0");
- (*currentPortStatus_1_2)[i].status_1_1.status.supportedModes = V1_0::PortMode::DRP;
- } else {
- if (version == HALVersion::V1_1)
- ALOGI("HAL version V1_1");
- else
- ALOGI("HAL version V1_2");
- (*currentPortStatus_1_2)[i].status_1_1.supportedModes = 0 | PortMode_1_1::DRP;
- (*currentPortStatus_1_2)[i].status_1_1.status.supportedModes = V1_0::PortMode::NONE;
- (*currentPortStatus_1_2)[i].status_1_1.status.currentMode = V1_0::PortMode::NONE;
- }
-
- ALOGI(
- "%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
- "supportedModes:%d",
- i, port.first.c_str(), port.second,
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangeMode,
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangeDataRole,
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangePowerRole,
- (*currentPortStatus_1_2)[i].status_1_1.supportedModes);
- }
- return Status::SUCCESS;
- }
-done:
- return Status::ERROR;
-}
-
-void queryVersionHelper(implementation::Usb *usb, hidl_vec<PortStatus> *currentPortStatus_1_2) {
- hidl_vec<V1_1::PortStatus_1_1> currentPortStatus_1_1;
- hidl_vec<V1_0::PortStatus> currentPortStatus;
- Status status;
- sp<V1_1::IUsbCallback> callback_V1_1 = V1_1::IUsbCallback::castFrom(usb->mCallback_1_0);
- sp<IUsbCallback> callback_V1_2 = IUsbCallback::castFrom(usb->mCallback_1_0);
-
- pthread_mutex_lock(&usb->mLock);
- if (usb->mCallback_1_0 != NULL) {
- if (callback_V1_2 != NULL) {
- status = getPortStatusHelper(currentPortStatus_1_2, HALVersion::V1_2);
- if (status == Status::SUCCESS)
- queryMoistureDetectionStatus(currentPortStatus_1_2);
- } else if (callback_V1_1 != NULL) {
- status = getPortStatusHelper(currentPortStatus_1_2, HALVersion::V1_1);
- currentPortStatus_1_1.resize(currentPortStatus_1_2->size());
- for (unsigned long i = 0; i < currentPortStatus_1_2->size(); i++)
- currentPortStatus_1_1[i] = (*currentPortStatus_1_2)[i].status_1_1;
- } else {
- status = getPortStatusHelper(currentPortStatus_1_2, HALVersion::V1_0);
- currentPortStatus.resize(currentPortStatus_1_2->size());
- for (unsigned long i = 0; i < currentPortStatus_1_2->size(); i++)
- currentPortStatus[i] = (*currentPortStatus_1_2)[i].status_1_1.status;
- }
-
- Return<void> ret;
-
- if (callback_V1_2 != NULL)
- ret = callback_V1_2->notifyPortStatusChange_1_2(*currentPortStatus_1_2, status);
- else if (callback_V1_1 != NULL)
- ret = callback_V1_1->notifyPortStatusChange_1_1(currentPortStatus_1_1, status);
- else
- ret = usb->mCallback_1_0->notifyPortStatusChange(currentPortStatus, status);
-
- if (!ret.isOk())
- ALOGE("queryPortStatus_1_2 error %s", ret.description().c_str());
- } else {
- ALOGI("Notifying userspace skipped. Callback is NULL");
- }
- pthread_mutex_unlock(&usb->mLock);
-}
-
-Return<void> Usb::queryPortStatus() {
- hidl_vec<PortStatus> currentPortStatus_1_2;
-
- queryVersionHelper(this, &currentPortStatus_1_2);
- return Void();
-}
-
-struct data {
- int uevent_fd;
- android::hardware::usb::V1_3::implementation::Usb *usb;
-};
-
-static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
- char msg[UEVENT_MSG_LEN + 2];
- char *cp;
- int n;
-
- n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
- if (n <= 0)
- return;
- if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
- return;
-
- msg[n] = '\0';
- msg[n + 1] = '\0';
- cp = msg;
-
- while (*cp) {
- if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
- ALOGI("partner added");
- pthread_mutex_lock(&payload->usb->mPartnerLock);
- payload->usb->mPartnerUp = true;
- pthread_cond_signal(&payload->usb->mPartnerCV);
- pthread_mutex_unlock(&payload->usb->mPartnerLock);
- } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_")) ||
- !strncmp(cp, "POWER_SUPPLY_MOISTURE_DETECTED",
- strlen("POWER_SUPPLY_MOISTURE_DETECTED"))) {
- hidl_vec<PortStatus> currentPortStatus_1_2;
- queryVersionHelper(payload->usb, &currentPortStatus_1_2);
-
- // Role switch is not in progress and port is in disconnected state
- if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
- for (unsigned long i = 0; i < currentPortStatus_1_2.size(); i++) {
- DIR *dp =
- opendir(std::string("/sys/class/typec/" +
- std::string(currentPortStatus_1_2[i]
- .status_1_1.status.portName.c_str()) +
- "-partner")
- .c_str());
- if (dp == NULL) {
- // PortRole role = {.role = static_cast<uint32_t>(PortMode::UFP)};
- switchToDrp(currentPortStatus_1_2[i].status_1_1.status.portName);
- } else {
- closedir(dp);
- }
- }
- pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
- }
- break;
- }
- /* advance to after the next \0 */
- while (*cp++) {
- }
- }
-}
-
-void *work(void *param) {
- int epoll_fd, uevent_fd;
- struct epoll_event ev;
- int nevents = 0;
- struct data payload;
-
- ALOGE("creating thread");
-
- uevent_fd = uevent_open_socket(64 * 1024, true);
-
- if (uevent_fd < 0) {
- ALOGE("uevent_init: uevent_open_socket failed\n");
- return NULL;
- }
-
- payload.uevent_fd = uevent_fd;
- payload.usb = (android::hardware::usb::V1_3::implementation::Usb *)param;
-
- fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
-
- ev.events = EPOLLIN;
- ev.data.ptr = (void *)uevent_event;
-
- epoll_fd = epoll_create(64);
- if (epoll_fd == -1) {
- ALOGE("epoll_create failed; errno=%d", errno);
- goto error;
- }
-
- if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
- ALOGE("epoll_ctl failed; errno=%d", errno);
- goto error;
- }
-
- while (!destroyThread) {
- struct epoll_event events[64];
-
- nevents = epoll_wait(epoll_fd, events, 64, -1);
- if (nevents == -1) {
- if (errno == EINTR)
- continue;
- ALOGE("usb epoll_wait failed; errno=%d", errno);
- break;
- }
-
- for (int n = 0; n < nevents; ++n) {
- if (events[n].data.ptr)
- (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events,
- &payload);
- }
- }
-
- ALOGI("exiting worker thread");
-error:
- close(uevent_fd);
-
- if (epoll_fd >= 0)
- close(epoll_fd);
-
- return NULL;
-}
-
-void sighandler(int sig) {
- if (sig == SIGUSR1) {
- destroyThread = true;
- ALOGI("destroy set");
- return;
- }
- signal(SIGUSR1, sighandler);
-}
-
-Return<void> Usb::setCallback(const sp<V1_0::IUsbCallback> &callback) {
- sp<V1_1::IUsbCallback> callback_V1_1 = V1_1::IUsbCallback::castFrom(callback);
- sp<IUsbCallback> callback_V1_2 = IUsbCallback::castFrom(callback);
-
- if (callback != NULL) {
- if (callback_V1_2 != NULL)
- ALOGI("Registering 1.2 callback");
- else if (callback_V1_1 != NULL)
- ALOGI("Registering 1.1 callback");
- }
-
- pthread_mutex_lock(&mLock);
- /*
- * When both the old callback and new callback values are NULL,
- * there is no need to spin off the worker thread.
- * When both the values are not NULL, we would already have a
- * worker thread running, so updating the callback object would
- * be suffice.
- */
- if ((mCallback_1_0 == NULL && callback == NULL) ||
- (mCallback_1_0 != NULL && callback != NULL)) {
- /*
- * Always store as V1_0 callback object. Type cast to V1_1
- * when the callback is actually invoked.
- */
- mCallback_1_0 = callback;
- pthread_mutex_unlock(&mLock);
- return Void();
- }
-
- mCallback_1_0 = callback;
- ALOGI("registering callback");
-
- // Kill the worker thread if the new callback is NULL.
- if (mCallback_1_0 == NULL) {
- pthread_mutex_unlock(&mLock);
- if (!pthread_kill(mPoll, SIGUSR1)) {
- pthread_join(mPoll, NULL);
- ALOGI("pthread destroyed");
- }
- return Void();
- }
-
- destroyThread = false;
- signal(SIGUSR1, sighandler);
-
- /*
- * Create a background thread if the old callback value is NULL
- * and being updated with a new value.
- */
- if (pthread_create(&mPoll, NULL, work, this)) {
- ALOGE("pthread creation failed %d", errno);
- mCallback_1_0 = NULL;
- }
-
- pthread_mutex_unlock(&mLock);
- return Void();
-}
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace usb
-} // namespace hardware
-} // namespace android
diff --git a/usb/Usb.h b/usb/Usb.h
deleted file mode 100644
index 5ff110d..0000000
--- a/usb/Usb.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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 <android-base/file.h>
-#include <android/hardware/usb/1.2/IUsbCallback.h>
-#include <android/hardware/usb/1.2/types.h>
-#include <android/hardware/usb/1.3/IUsb.h>
-#include <hidl/Status.h>
-#include <pixelusb/UsbGadgetCommon.h>
-#include <utils/Log.h>
-
-#define UEVENT_MSG_LEN 2048
-// The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd.
-// The -partner directory would not be created until this is done.
-// Having a margin of ~3 secs for the directory and other related bookeeping
-// structures created and uvent fired.
-#define PORT_TYPE_TIMEOUT 8
-
-namespace android {
-namespace hardware {
-namespace usb {
-namespace V1_3 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::base::WriteStringToFile;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::usb::V1_0::PortDataRole;
-using ::android::hardware::usb::V1_0::PortPowerRole;
-using ::android::hardware::usb::V1_0::PortRole;
-using ::android::hardware::usb::V1_0::PortRoleType;
-using ::android::hardware::usb::V1_0::Status;
-using ::android::hardware::usb::V1_1::PortMode_1_1;
-using ::android::hardware::usb::V1_1::PortStatus_1_1;
-using ::android::hardware::usb::V1_2::PortStatus;
-using ::android::hardware::usb::V1_2::IUsbCallback;
-using ::android::hardware::usb::V1_3::IUsb;
-using ::android::hidl::base::V1_0::DebugInfo;
-using ::android::hidl::base::V1_0::IBase;
-
-enum class HALVersion{
- V1_0,
- V1_1,
- V1_2,
- V1_3
-};
-
-constexpr char kGadgetName[] = "a600000.dwc3";
-#define SOC_PATH "/sys/devices/platform/soc/a600000.ssusb/"
-#define ID_PATH SOC_PATH "id"
-#define VBUS_PATH SOC_PATH "b_sess"
-#define USB_DATA_PATH SOC_PATH "usb_data_enabled"
-
-struct Usb : public IUsb {
- Usb();
-
- Return<void> switchRole(const hidl_string &portName, const V1_0::PortRole &role) override;
- Return<void> setCallback(const sp<V1_0::IUsbCallback> &callback) override;
- Return<void> queryPortStatus() override;
- Return<void> enableContaminantPresenceDetection(const hidl_string& portName, bool enable);
- Return<void> enableContaminantPresenceProtection(const hidl_string& portName, bool enable);
- Return<bool> enableUsbDataSignal(bool enable) override;
-
- sp<V1_0::IUsbCallback> mCallback_1_0;
- // Protects mCallback variable
- pthread_mutex_t mLock;
- // Protects roleSwitch operation
- pthread_mutex_t mRoleSwitchLock;
- // Threads waiting for the partner to come back wait here
- pthread_cond_t mPartnerCV;
- // lock protecting mPartnerCV
- pthread_mutex_t mPartnerLock;
- // Variable to signal partner coming back online after type switch
- bool mPartnerUp;
-
- private:
- pthread_t mPoll;
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace usb
-} // namespace hardware
-} // namespace android
diff --git a/usb/Android.bp b/usb/gadget/Android.bp
index 03b0c92..756b9eb 100644
--- a/usb/Android.bp
+++ b/usb/gadget/Android.bp
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2018 The Android Open Source Project
+// 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.
@@ -18,19 +18,14 @@ package {
}
cc_binary {
- name: "android.hardware.usb@1.3-service.redfin",
+ name: "android.hardware.usb.gadget-service.redfin",
relative_install_path: "hw",
- init_rc: ["android.hardware.usb@1.3-service.redfin.rc"],
+ init_rc: ["android.hardware.usb.gadget-service.redfin.rc"],
vintf_fragments: [
- "android.hardware.usb@1.3-service.redfin.xml",
"android.hardware.usb.gadget@1.1-service.redfin.xml",
],
- srcs: ["service.cpp", "Usb.cpp", "UsbGadget.cpp"],
+ srcs: ["service_gadget.cpp", "UsbGadget.cpp"],
shared_libs: [
- "android.hardware.usb@1.0",
- "android.hardware.usb@1.1",
- "android.hardware.usb@1.2",
- "android.hardware.usb@1.3",
"android.hardware.usb.gadget@1.0",
"android.hardware.usb.gadget@1.1",
"libbase",
diff --git a/usb/UsbGadget.cpp b/usb/gadget/UsbGadget.cpp
index 97535f0..97535f0 100644
--- a/usb/UsbGadget.cpp
+++ b/usb/gadget/UsbGadget.cpp
diff --git a/usb/UsbGadget.h b/usb/gadget/UsbGadget.h
index 93c7d66..93c7d66 100644
--- a/usb/UsbGadget.h
+++ b/usb/gadget/UsbGadget.h
diff --git a/usb/android.hardware.usb@1.3-service.redfin.rc b/usb/gadget/android.hardware.usb.gadget-service.redfin.rc
index fffa93a..5e61e87 100644
--- a/usb/android.hardware.usb@1.3-service.redfin.rc
+++ b/usb/gadget/android.hardware.usb.gadget-service.redfin.rc
@@ -1,4 +1,4 @@
-service vendor.usb-hal-1-3 /vendor/bin/hw/android.hardware.usb@1.3-service.redfin
+service vendor.usb-gadget-hal-1-1 /vendor/bin/hw/android.hardware.usb.gadget-service.redfin
class hal
user system
group system shell mtp
diff --git a/usb/android.hardware.usb.gadget@1.1-service.redfin.xml b/usb/gadget/android.hardware.usb.gadget@1.1-service.redfin.xml
index a6f9a1f..a6f9a1f 100644
--- a/usb/android.hardware.usb.gadget@1.1-service.redfin.xml
+++ b/usb/gadget/android.hardware.usb.gadget@1.1-service.redfin.xml
diff --git a/usb/service.cpp b/usb/gadget/service_gadget.cpp
index 570beef..159e8f2 100644
--- a/usb/service.cpp
+++ b/usb/gadget/service_gadget.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 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.
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-#define LOG_TAG "android.hardware.usb@1.3-service.redfin"
+#define LOG_TAG "android.hardware.usb.gadget-service.redfin"
#include <hidl/HidlTransportSupport.h>
-#include "Usb.h"
#include "UsbGadget.h"
using android::sp;
@@ -29,34 +28,23 @@ using android::hardware::joinRpcThreadpool;
// Generated HIDL files
using android::hardware::usb::gadget::V1_1::IUsbGadget;
using android::hardware::usb::gadget::V1_1::implementation::UsbGadget;
-using android::hardware::usb::V1_3::IUsb;
-using android::hardware::usb::V1_3::implementation::Usb;
using android::OK;
using android::status_t;
int main() {
- android::sp<IUsb> service = new Usb();
- android::sp<IUsbGadget> service2 = new UsbGadget();
-
+ android::sp<IUsbGadget> service = new UsbGadget();
configureRpcThreadpool(2, true /*callerWillJoin*/);
status_t status = service->registerAsService();
if (status != OK) {
- ALOGE("Cannot register USB HAL service");
- return 1;
- }
-
- status = service2->registerAsService();
-
- if (status != OK) {
ALOGE("Cannot register USB Gadget HAL service");
return 1;
}
- ALOGI("USB HAL Ready.");
+ ALOGI("USB gadget HAL Ready.");
joinRpcThreadpool();
// Under noraml cases, execution will not reach this line.
- ALOGI("USB HAL failed to join thread pool.");
+ ALOGI("USB gadget HAL failed to join thread pool.");
return 1;
}
diff --git a/usb/usb/Android.bp b/usb/usb/Android.bp
new file mode 100644
index 0000000..4f5d599
--- /dev/null
+++ b/usb/usb/Android.bp
@@ -0,0 +1,50 @@
+//
+// 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.
+//
+
+cc_binary {
+ name: "android.hardware.usb-service.redfin",
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.usb-service.rc"],
+ vintf_fragments: ["android.hardware.usb-service.xml"],
+ vendor: true,
+ srcs: [
+ "service.cpp",
+ "Usb.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "libhardware",
+ "android.hardware.usb.gadget@1.0",
+ "android.hardware.usb-V1-ndk",
+ "libcutils",
+ "android.frameworks.stats-V1-ndk",
+ "pixelatoms-cpp",
+ "libbinder_ndk",
+
+ ],
+ static_libs: [
+ "libpixelusb",
+ "libpixelstats",
+ ],
+ export_shared_lib_headers: [
+ "android.frameworks.stats-V1-ndk",
+ "pixelatoms-cpp",
+ ],
+}
diff --git a/usb/usb/Usb.cpp b/usb/usb/Usb.cpp
new file mode 100644
index 0000000..8d4cb47
--- /dev/null
+++ b/usb/usb/Usb.cpp
@@ -0,0 +1,835 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "android.hardware.usb.aidl-service"
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <assert.h>
+#include <dirent.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <chrono>
+#include <regex>
+#include <thread>
+#include <unordered_map>
+
+#include <cutils/uevent.h>
+#include <sys/epoll.h>
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+
+#include "Usb.h"
+
+using android::base::GetProperty;
+using android::base::Trim;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace usb {
+
+// Set by the signal handler to destroy the thread
+volatile bool destroyThread;
+
+constexpr char kConsole[] = "init.svc.console";
+constexpr char kDetectedPath[] = "/sys/class/power_supply/usb/moisture_detected";
+constexpr char kDisableContatminantDetection[] = "vendor.usb.contaminantdisable";
+constexpr char kEnabledPath[] = "/sys/class/power_supply/usb/moisture_detection_enabled";
+constexpr char kTypecPath[] = "/sys/class/typec";
+
+void queryVersionHelper(android::hardware::usb::Usb *usb,
+ std::vector<PortStatus> *currentPortStatus);
+
+ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable,
+ int64_t in_transactionId) {
+ bool result = true;
+ std::vector<PortStatus> currentPortStatus;
+
+ ALOGI("Userspace turn %s USB data signaling. opID:%ld", in_enable ? "on" : "off",
+ in_transactionId);
+
+ if (in_enable) {
+ if (!WriteStringToFile("1", USB_DATA_PATH)) {
+ ALOGE("Not able to turn on usb connection notification");
+ result = false;
+ }
+
+ if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
+ ALOGE("Gadget cannot be pulled up");
+ result = false;
+ }
+ } else {
+ if (!WriteStringToFile("1", ID_PATH)) {
+ ALOGE("Not able to turn off host mode");
+ result = false;
+ }
+
+ if (!WriteStringToFile("0", VBUS_PATH)) {
+ ALOGE("Not able to set Vbus state");
+ result = false;
+ }
+
+ if (!WriteStringToFile("0", USB_DATA_PATH)) {
+ ALOGE("Not able to turn on usb connection notification");
+ result = false;
+ }
+
+ if (!WriteStringToFile("none", PULLUP_PATH)) {
+ ALOGE("Gadget cannot be pulled down");
+ result = false;
+ }
+ }
+
+ if (result) {
+ mUsbDataEnabled = in_enable;
+ }
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ScopedAStatus ret = mCallback->notifyEnableUsbDataStatus(
+ in_portName, in_enable, result ? Status::SUCCESS : Status::ERROR, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+ queryVersionHelper(this, &currentPortStatus);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Usb::enableUsbDataWhileDocked(const string& in_portName,
+ int64_t in_transactionId) {
+ std::vector<PortStatus> currentPortStatus;
+
+ ALOGI("Userspace enableUsbDataWhileDocked opID:%ld", in_transactionId);
+
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ScopedAStatus ret = mCallback->notifyEnableUsbDataWhileDockedStatus(
+ in_portName, Status::NOT_SUPPORTED, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+ queryVersionHelper(this, &currentPortStatus);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Usb::resetUsbPort(const std::string& in_portName, int64_t in_transactionId) {
+ bool result = true;
+ std::vector<PortStatus> currentPortStatus;
+
+ ALOGI("Userspace reset USB Port. opID:%ld", in_transactionId);
+
+ if (!WriteStringToFile("none", PULLUP_PATH)) {
+ ALOGI("Gadget cannot be pulled down");
+ result = false;
+ }
+
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ::ndk::ScopedAStatus ret = mCallback->notifyResetUsbPortStatus(
+ in_portName, result ? Status::SUCCESS : Status::ERROR, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("notifyTransactionStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+
+ return ::ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus Usb::limitPowerTransfer(const string& in_portName, bool in_limit,
+ int64_t in_transactionId) {
+ std::vector<PortStatus> currentPortStatus;
+
+ ALOGI("limitPowerTransfer limit:%c opId:%ld", in_limit ? 'y' : 'n', in_transactionId);
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL && in_transactionId >= 0) {
+ ScopedAStatus ret = mCallback->notifyLimitPowerTransferStatus(
+ in_portName, in_limit, Status::NOT_SUPPORTED, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("limitPowerTransfer error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+
+ pthread_mutex_unlock(&mLock);
+ queryVersionHelper(this, &currentPortStatus);
+
+ return ScopedAStatus::ok();
+}
+
+Status queryMoistureDetectionStatus(std::vector<PortStatus> *currentPortStatus) {
+ string enabled, status, path, DetectedPath;
+
+ (*currentPortStatus)[0].supportedContaminantProtectionModes
+ .push_back(ContaminantProtectionMode::FORCE_DISABLE);
+ (*currentPortStatus)[0].contaminantProtectionStatus = ContaminantProtectionStatus::NONE;
+ (*currentPortStatus)[0].contaminantDetectionStatus = ContaminantDetectionStatus::DISABLED;
+ (*currentPortStatus)[0].supportsEnableContaminantPresenceDetection = true;
+ (*currentPortStatus)[0].supportsEnableContaminantPresenceProtection = false;
+
+ if (!ReadFileToString(kEnabledPath, &enabled)) {
+ ALOGE("Failed to open moisture_detection_enabled");
+ return Status::ERROR;
+ }
+
+ enabled = Trim(enabled);
+ if (enabled == "1") {
+ if (!ReadFileToString(kDetectedPath, &status)) {
+ ALOGE("Failed to open moisture_detected");
+ return Status::ERROR;
+ }
+ status = Trim(status);
+ if (status == "1") {
+ (*currentPortStatus)[0].contaminantDetectionStatus =
+ ContaminantDetectionStatus::DETECTED;
+ (*currentPortStatus)[0].contaminantProtectionStatus =
+ ContaminantProtectionStatus::FORCE_DISABLE;
+ } else {
+ (*currentPortStatus)[0].contaminantDetectionStatus =
+ ContaminantDetectionStatus::NOT_DETECTED;
+ }
+ }
+
+ ALOGI("ContaminantDetectionStatus:%d ContaminantProtectionStatus:%d",
+ (*currentPortStatus)[0].contaminantDetectionStatus,
+ (*currentPortStatus)[0].contaminantProtectionStatus);
+
+ return Status::SUCCESS;
+}
+
+string appendRoleNodeHelper(const string &portName, PortRole::Tag tag) {
+ string node("/sys/class/typec/" + portName);
+
+ switch (tag) {
+ case PortRole::dataRole:
+ return node + "/data_role";
+ case PortRole::powerRole:
+ return node + "/power_role";
+ case PortRole::mode:
+ return node + "/port_type";
+ default:
+ return "";
+ }
+}
+
+string convertRoletoString(PortRole role) {
+ if (role.getTag() == PortRole::powerRole) {
+ if (role.get<PortRole::powerRole>() == PortPowerRole::SOURCE)
+ return "source";
+ else if (role.get<PortRole::powerRole>() == PortPowerRole::SINK)
+ return "sink";
+ } else if (role.getTag() == PortRole::dataRole) {
+ if (role.get<PortRole::dataRole>() == PortDataRole::HOST)
+ return "host";
+ if (role.get<PortRole::dataRole>() == PortDataRole::DEVICE)
+ return "device";
+ } else if (role.getTag() == PortRole::mode) {
+ if (role.get<PortRole::mode>() == PortMode::UFP)
+ return "sink";
+ if (role.get<PortRole::mode>() == PortMode::DFP)
+ return "source";
+ }
+ return "none";
+}
+
+void extractRole(string *roleName) {
+ std::size_t first, last;
+
+ first = roleName->find("[");
+ last = roleName->find("]");
+
+ if (first != string::npos && last != string::npos) {
+ *roleName = roleName->substr(first + 1, last - first - 1);
+ }
+}
+
+void switchToDrp(const string &portName) {
+ string filename = appendRoleNodeHelper(string(portName.c_str()), PortRole::mode);
+ FILE *fp;
+
+ if (filename != "") {
+ fp = fopen(filename.c_str(), "w");
+ if (fp != NULL) {
+ int ret = fputs("dual", fp);
+ fclose(fp);
+ if (ret == EOF)
+ ALOGE("Fatal: Error while switching back to drp");
+ } else {
+ ALOGE("Fatal: Cannot open file to switch back to drp");
+ }
+ } else {
+ ALOGE("Fatal: invalid node type");
+ }
+}
+
+bool switchMode(const string &portName, const PortRole &in_role, struct Usb *usb) {
+ string filename = appendRoleNodeHelper(string(portName.c_str()), in_role.getTag());
+ string written;
+ FILE *fp;
+ bool roleSwitch = false;
+
+ if (filename == "") {
+ ALOGE("Fatal: invalid node type");
+ return false;
+ }
+
+ fp = fopen(filename.c_str(), "w");
+ if (fp != NULL) {
+ // Hold the lock here to prevent loosing connected signals
+ // as once the file is written the partner added signal
+ // can arrive anytime.
+ pthread_mutex_lock(&usb->mPartnerLock);
+ usb->mPartnerUp = false;
+ int ret = fputs(convertRoletoString(in_role).c_str(), fp);
+ fclose(fp);
+
+ if (ret != EOF) {
+ struct timespec to;
+ struct timespec now;
+
+ wait_again:
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
+ to.tv_nsec = now.tv_nsec;
+
+ int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
+ // There are no uevent signals which implies role swap timed out.
+ if (err == ETIMEDOUT) {
+ ALOGI("uevents wait timedout");
+ // Validity check.
+ } else if (!usb->mPartnerUp) {
+ goto wait_again;
+ // Role switch succeeded since usb->mPartnerUp is true.
+ } else {
+ roleSwitch = true;
+ }
+ } else {
+ ALOGI("Role switch failed while wrting to file");
+ }
+ pthread_mutex_unlock(&usb->mPartnerLock);
+ }
+
+ if (!roleSwitch)
+ switchToDrp(string(portName.c_str()));
+
+ return roleSwitch;
+}
+
+Usb::Usb()
+ : mLock(PTHREAD_MUTEX_INITIALIZER),
+ mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
+ mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
+ mPartnerUp(false) {
+ pthread_condattr_t attr;
+ if (pthread_condattr_init(&attr)) {
+ ALOGE("pthread_condattr_init failed: %s", strerror(errno));
+ abort();
+ }
+ if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
+ ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
+ abort();
+ }
+ if (pthread_cond_init(&mPartnerCV, &attr)) {
+ ALOGE("pthread_cond_init failed: %s", strerror(errno));
+ abort();
+ }
+ if (pthread_condattr_destroy(&attr)) {
+ ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
+ abort();
+ }
+}
+
+ScopedAStatus Usb::switchRole(const string& in_portName, const PortRole& in_role,
+ int64_t in_transactionId) {
+ string filename = appendRoleNodeHelper(string(in_portName.c_str()), in_role.getTag());
+ string written;
+ FILE *fp;
+ bool roleSwitch = false;
+
+ if (filename == "") {
+ ALOGE("Fatal: invalid node type");
+ return ScopedAStatus::ok();
+ }
+
+ pthread_mutex_lock(&mRoleSwitchLock);
+
+ ALOGI("filename write: %s role:%s", filename.c_str(), convertRoletoString(in_role).c_str());
+
+ if (in_role.getTag() == PortRole::mode) {
+ roleSwitch = switchMode(in_portName, in_role, this);
+ } else {
+ fp = fopen(filename.c_str(), "w");
+ if (fp != NULL) {
+ int ret = fputs(convertRoletoString(in_role).c_str(), fp);
+ fclose(fp);
+ if ((ret != EOF) && ReadFileToString(filename, &written)) {
+ written = Trim(written);
+ extractRole(&written);
+ ALOGI("written: %s", written.c_str());
+ if (written == convertRoletoString(in_role)) {
+ roleSwitch = true;
+ } else {
+ ALOGE("Role switch failed");
+ }
+ } else {
+ ALOGE("failed to update the new role");
+ }
+ } else {
+ ALOGE("fopen failed");
+ }
+ }
+
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ScopedAStatus ret = mCallback->notifyRoleSwitchStatus(
+ in_portName, in_role, roleSwitch ? Status::SUCCESS : Status::ERROR, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("RoleSwitchStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+ pthread_mutex_unlock(&mRoleSwitchLock);
+
+ return ScopedAStatus::ok();
+}
+
+Status getAccessoryConnected(const string &portName, string *accessory) {
+ string filename = "/sys/class/typec/" + portName + "-partner/accessory_mode";
+
+ if (!ReadFileToString(filename, accessory)) {
+ ALOGE("getAccessoryConnected: Failed to open filesystem node: %s", filename.c_str());
+ return Status::ERROR;
+ }
+ *accessory = Trim(*accessory);
+
+ return Status::SUCCESS;
+}
+
+Status getCurrentRoleHelper(const string &portName, bool connected, PortRole *currentRole) {
+ string filename;
+ string roleName;
+ string accessory;
+
+ if (currentRole->getTag() == PortRole::powerRole) {
+ filename = "/sys/class/typec/" + portName + "/power_role";
+ currentRole->set<PortRole::powerRole>(PortPowerRole::NONE);
+ } else if (currentRole->getTag() == PortRole::dataRole) {
+ filename = "/sys/class/typec/" + portName + "/data_role";
+ currentRole->set<PortRole::dataRole>(PortDataRole::NONE);
+ } else if (currentRole->getTag() == PortRole::mode) {
+ filename = "/sys/class/typec/" + portName + "/data_role";
+ currentRole->set<PortRole::mode>(PortMode::NONE);
+ } else {
+ return Status::ERROR;
+ }
+
+ if (!connected)
+ return Status::SUCCESS;
+
+ if (currentRole->getTag() == PortRole::mode) {
+ if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
+ return Status::ERROR;
+ }
+ if (accessory == "analog_audio") {
+ currentRole->set<PortRole::mode>(PortMode::AUDIO_ACCESSORY);
+ return Status::SUCCESS;
+ } else if (accessory == "debug") {
+ currentRole->set<PortRole::mode>(PortMode::DEBUG_ACCESSORY);
+ return Status::SUCCESS;
+ }
+ }
+
+ if (!ReadFileToString(filename, &roleName)) {
+ ALOGE("getCurrentRole: Failed to open filesystem node: %s", filename.c_str());
+ return Status::ERROR;
+ }
+
+ roleName = Trim(roleName);
+ extractRole(&roleName);
+
+ if (roleName == "source") {
+ currentRole->set<PortRole::powerRole>(PortPowerRole::SOURCE);
+ } else if (roleName == "sink") {
+ currentRole->set<PortRole::powerRole>(PortPowerRole::SINK);
+ } else if (roleName == "host") {
+ if (currentRole->getTag() == PortRole::dataRole)
+ currentRole->set<PortRole::dataRole>(PortDataRole::HOST);
+ else
+ currentRole->set<PortRole::mode>(PortMode::DFP);
+ } else if (roleName == "device") {
+ if (currentRole->getTag() == PortRole::dataRole)
+ currentRole->set<PortRole::dataRole>(PortDataRole::DEVICE);
+ else
+ currentRole->set<PortRole::mode>(PortMode::UFP);
+ } else if (roleName != "none") {
+ /* case for none has already been addressed.
+ * so we check if the role isn't none.
+ */
+ return Status::UNRECOGNIZED_ROLE;
+ }
+ return Status::SUCCESS;
+}
+
+Status getTypeCPortNamesHelper(std::unordered_map<string, bool> *names) {
+ DIR *dp;
+
+ dp = opendir(kTypecPath);
+ if (dp != NULL) {
+ struct dirent *ep;
+
+ while ((ep = readdir(dp))) {
+ if (ep->d_type == DT_LNK) {
+ if (string::npos == string(ep->d_name).find("-partner")) {
+ std::unordered_map<string, bool>::const_iterator portName =
+ names->find(ep->d_name);
+ if (portName == names->end()) {
+ names->insert({ep->d_name, false});
+ }
+ } else {
+ (*names)[std::strtok(ep->d_name, "-")] = true;
+ }
+ }
+ }
+ closedir(dp);
+ return Status::SUCCESS;
+ }
+
+ ALOGE("Failed to open /sys/class/typec");
+ return Status::ERROR;
+}
+
+bool canSwitchRoleHelper(const string &portName) {
+ string filename = "/sys/class/typec/" + portName + "-partner/supports_usb_power_delivery";
+ string supportsPD;
+
+ if (ReadFileToString(filename, &supportsPD)) {
+ supportsPD = Trim(supportsPD);
+ if (supportsPD == "yes") {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Status getPortStatusHelper(android::hardware::usb::Usb *usb,
+ std::vector<PortStatus> *currentPortStatus) {
+ std::unordered_map<string, bool> names;
+ Status result = getTypeCPortNamesHelper(&names);
+ int i = -1;
+
+ if (result == Status::SUCCESS) {
+ currentPortStatus->resize(names.size());
+ for (std::pair<string, bool> port : names) {
+ i++;
+ ALOGI("%s", port.first.c_str());
+ (*currentPortStatus)[i].portName = port.first;
+
+ PortRole currentRole;
+ currentRole.set<PortRole::powerRole>(PortPowerRole::NONE);
+ if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS){
+ (*currentPortStatus)[i].currentPowerRole = currentRole.get<PortRole::powerRole>();
+ } else {
+ ALOGE("Error while retrieving portNames");
+ goto done;
+ }
+
+ currentRole.set<PortRole::dataRole>(PortDataRole::NONE);
+ if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
+ (*currentPortStatus)[i].currentDataRole = currentRole.get<PortRole::dataRole>();
+ } else {
+ ALOGE("Error while retrieving current port role");
+ goto done;
+ }
+
+ currentRole.set<PortRole::mode>(PortMode::NONE);
+ if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
+ (*currentPortStatus)[i].currentMode = currentRole.get<PortRole::mode>();
+ } else {
+ ALOGE("Error while retrieving current data role");
+ goto done;
+ }
+
+ (*currentPortStatus)[i].canChangeMode = true;
+ (*currentPortStatus)[i].canChangeDataRole =
+ port.second ? canSwitchRoleHelper(port.first) : false;
+ (*currentPortStatus)[i].canChangePowerRole =
+ port.second ? canSwitchRoleHelper(port.first) : false;
+
+ (*currentPortStatus)[i].supportedModes.push_back(PortMode::DRP);
+
+ if (!usb->mUsbDataEnabled) {
+ (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::DISABLED_FORCE);
+ } else {
+ (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::ENABLED);
+ }
+ (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::UNKNOWN;
+
+ ALOGI("%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
+ "usbDataEnabled:%d",
+ i, port.first.c_str(), port.second,
+ (*currentPortStatus)[i].canChangeMode,
+ (*currentPortStatus)[i].canChangeDataRole,
+ (*currentPortStatus)[i].canChangePowerRole,
+ usb->mUsbDataEnabled ? 1 : 0);
+ }
+ return Status::SUCCESS;
+ }
+done:
+ return Status::ERROR;
+}
+
+void queryVersionHelper(android::hardware::usb::Usb *usb,
+ std::vector<PortStatus> *currentPortStatus) {
+ Status status;
+ pthread_mutex_lock(&usb->mLock);
+ status = getPortStatusHelper(usb, currentPortStatus);
+ queryMoistureDetectionStatus(currentPortStatus);
+ if (usb->mCallback != NULL) {
+ ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
+ status);
+ if (!ret.isOk())
+ ALOGE("queryPortStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGI("Notifying userspace skipped. Callback is NULL");
+ }
+ pthread_mutex_unlock(&usb->mLock);
+}
+
+ScopedAStatus Usb::queryPortStatus(int64_t in_transactionId) {
+ std::vector<PortStatus> currentPortStatus;
+
+ queryVersionHelper(this, &currentPortStatus);
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ScopedAStatus ret = mCallback->notifyQueryPortStatus(
+ "all", Status::SUCCESS, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("notifyQueryPortStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Usb::enableContaminantPresenceDetection(const string& in_portName,
+ bool in_enable, int64_t in_transactionId) {
+ string disable = GetProperty(kDisableContatminantDetection, "");
+ std::string status = GetProperty(kConsole, "");
+ std::vector<PortStatus> currentPortStatus;
+ bool success = true;
+
+ if (status != "running" && disable != "true")
+ success = WriteStringToFile(in_enable ? "1" : "0", kEnabledPath);
+
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ScopedAStatus ret = mCallback->notifyContaminantEnabledStatus(
+ in_portName, in_enable, success ? Status::SUCCESS : Status::ERROR, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("notifyContaminantEnabledStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+
+ queryVersionHelper(this, &currentPortStatus);
+ return ScopedAStatus::ok();
+}
+
+struct data {
+ int uevent_fd;
+ ::aidl::android::hardware::usb::Usb *usb;
+};
+
+static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
+ char msg[UEVENT_MSG_LEN + 2];
+ char *cp;
+ int n;
+
+ n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
+ if (n <= 0)
+ return;
+ if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
+ return;
+
+ msg[n] = '\0';
+ msg[n + 1] = '\0';
+ cp = msg;
+
+ while (*cp) {
+ if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
+ ALOGI("partner added");
+ pthread_mutex_lock(&payload->usb->mPartnerLock);
+ payload->usb->mPartnerUp = true;
+ pthread_cond_signal(&payload->usb->mPartnerCV);
+ pthread_mutex_unlock(&payload->usb->mPartnerLock);
+ } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_")) ||
+ !strncmp(cp, "POWER_SUPPLY_MOISTURE_DETECTED",
+ strlen("POWER_SUPPLY_MOISTURE_DETECTED"))) {
+ std::vector<PortStatus> currentPortStatus;
+ queryVersionHelper(payload->usb, &currentPortStatus);
+
+ // Role switch is not in progress and port is in disconnected state
+ if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
+ for (unsigned long i = 0; i < currentPortStatus.size(); i++) {
+ DIR *dp =
+ opendir(string("/sys/class/typec/" +
+ string(currentPortStatus[i].portName.c_str()) +
+ "-partner").c_str());
+ if (dp == NULL) {
+ switchToDrp(currentPortStatus[i].portName);
+ } else {
+ closedir(dp);
+ }
+ }
+ pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
+ }
+ break;
+ }
+ /* advance to after the next \0 */
+ while (*cp++) {
+ }
+ }
+}
+
+void *work(void *param) {
+ int epoll_fd, uevent_fd;
+ struct epoll_event ev;
+ int nevents = 0;
+ struct data payload;
+
+ ALOGE("creating thread");
+
+ uevent_fd = uevent_open_socket(64 * 1024, true);
+
+ if (uevent_fd < 0) {
+ ALOGE("uevent_init: uevent_open_socket failed\n");
+ return NULL;
+ }
+
+ payload.uevent_fd = uevent_fd;
+ payload.usb = (::aidl::android::hardware::usb::Usb *)param;
+
+ fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+
+ ev.events = EPOLLIN;
+ ev.data.ptr = (void *)uevent_event;
+
+ epoll_fd = epoll_create(64);
+ if (epoll_fd == -1) {
+ ALOGE("epoll_create failed; errno=%d", errno);
+ goto error;
+ }
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
+ ALOGE("epoll_ctl failed; errno=%d", errno);
+ goto error;
+ }
+
+ while (!destroyThread) {
+ struct epoll_event events[64];
+
+ nevents = epoll_wait(epoll_fd, events, 64, -1);
+ if (nevents == -1) {
+ if (errno == EINTR)
+ continue;
+ ALOGE("usb epoll_wait failed; errno=%d", errno);
+ break;
+ }
+
+ for (int n = 0; n < nevents; ++n) {
+ if (events[n].data.ptr)
+ (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events,
+ &payload);
+ }
+ }
+
+ ALOGI("exiting worker thread");
+error:
+ close(uevent_fd);
+
+ if (epoll_fd >= 0)
+ close(epoll_fd);
+
+ return NULL;
+}
+
+void sighandler(int sig) {
+ if (sig == SIGUSR1) {
+ destroyThread = true;
+ ALOGI("destroy set");
+ return;
+ }
+ signal(SIGUSR1, sighandler);
+}
+
+ScopedAStatus Usb::setCallback(const shared_ptr<IUsbCallback>& in_callback) {
+ pthread_mutex_lock(&mLock);
+ if ((mCallback == NULL && in_callback == NULL) ||
+ (mCallback != NULL && in_callback != NULL)) {
+ mCallback = in_callback;
+ pthread_mutex_unlock(&mLock);
+ return ScopedAStatus::ok();
+ }
+
+ mCallback = in_callback;
+ ALOGI("registering callback");
+
+ if (mCallback == NULL) {
+ if (!pthread_kill(mPoll, SIGUSR1)) {
+ pthread_join(mPoll, NULL);
+ ALOGI("pthread destroyed");
+ }
+ pthread_mutex_unlock(&mLock);
+ return ScopedAStatus::ok();
+ }
+
+ destroyThread = false;
+ signal(SIGUSR1, sighandler);
+
+ /*
+ * Create a background thread if the old callback value is NULL
+ * and being updated with a new value.
+ */
+ if (pthread_create(&mPoll, NULL, work, this)) {
+ ALOGE("pthread creation failed %d", errno);
+ mCallback = NULL;
+ }
+
+ pthread_mutex_unlock(&mLock);
+ return ScopedAStatus::ok();
+}
+
+} // namespace usb
+} // namespace hardware
+} // namespace android
+} // aidl
diff --git a/usb/usb/Usb.h b/usb/usb/Usb.h
new file mode 100644
index 0000000..0cd9699
--- /dev/null
+++ b/usb/usb/Usb.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 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-base/file.h>
+#include <aidl/android/hardware/usb/BnUsb.h>
+#include <aidl/android/hardware/usb/BnUsbCallback.h>
+#include <utils/Log.h>
+
+#define UEVENT_MSG_LEN 2048
+// The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd.
+// The -partner directory would not be created until this is done.
+// Having a margin of ~3 secs for the directory and other related bookeeping
+// structures created and uvent fired.
+#define PORT_TYPE_TIMEOUT 8
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace usb {
+
+using ::aidl::android::hardware::usb::IUsbCallback;
+using ::aidl::android::hardware::usb::PortRole;
+using ::android::base::ReadFileToString;
+using ::android::base::WriteStringToFile;
+using ::android::sp;
+using ::ndk::ScopedAStatus;
+using ::std::shared_ptr;
+using ::std::string;
+
+constexpr char kGadgetName[] = "a600000.dwc3";
+#define ID_PATH SOC_PATH "id"
+#define PULLUP_PATH "/config/usb_gadget/g1/UDC"
+#define SOC_PATH "/sys/devices/platform/soc/a600000.ssusb/"
+#define USB_DATA_PATH SOC_PATH "usb_data_enabled"
+#define VBUS_PATH SOC_PATH "b_sess"
+
+struct Usb : public BnUsb {
+ Usb();
+
+ ScopedAStatus enableContaminantPresenceDetection(const std::string& in_portName,
+ bool in_enable, int64_t in_transactionId) override;
+ ScopedAStatus queryPortStatus(int64_t in_transactionId) override;
+ ScopedAStatus setCallback(const shared_ptr<IUsbCallback>& in_callback) override;
+ ScopedAStatus switchRole(const string& in_portName, const PortRole& in_role,
+ int64_t in_transactionId) override;
+ ScopedAStatus enableUsbData(const string& in_portName, bool in_enable,
+ int64_t in_transactionId) override;
+ ScopedAStatus enableUsbDataWhileDocked(const string& in_portName,
+ int64_t in_transactionId) override;
+ ScopedAStatus limitPowerTransfer(const string& in_portName, bool in_limit,
+ int64_t in_transactionId) override;
+ ScopedAStatus resetUsbPort(const string& in_portName, int64_t in_transactionId) override;
+
+ std::shared_ptr<::aidl::android::hardware::usb::IUsbCallback> mCallback;
+ // Protects mCallback variable
+ pthread_mutex_t mLock;
+ // Protects roleSwitch operation
+ pthread_mutex_t mRoleSwitchLock;
+ // Threads waiting for the partner to come back wait here
+ pthread_cond_t mPartnerCV;
+ // lock protecting mPartnerCV
+ pthread_mutex_t mPartnerLock;
+ // Variable to signal partner coming back online after type switch
+ bool mPartnerUp;
+ // Usb Data status
+ bool mUsbDataEnabled;
+
+ private:
+ pthread_t mPoll;
+};
+
+} // namespace usb
+} // namespace hardware
+} // namespace android
+} // aidl
diff --git a/usb/usb/android.hardware.usb-service.rc b/usb/usb/android.hardware.usb-service.rc
new file mode 100644
index 0000000..ec21fce
--- /dev/null
+++ b/usb/usb/android.hardware.usb-service.rc
@@ -0,0 +1,4 @@
+service vendor.usb /vendor/bin/hw/android.hardware.usb-service.redfin
+ class hal
+ user system
+ group system shell
diff --git a/usb/android.hardware.usb@1.3-service.redfin.xml b/usb/usb/android.hardware.usb-service.xml
index cd54268..6088194 100644
--- a/usb/android.hardware.usb@1.3-service.redfin.xml
+++ b/usb/usb/android.hardware.usb-service.xml
@@ -1,12 +1,10 @@
<manifest version="1.0" type="device">
- <hal format="hidl">
+ <hal format="aidl">
<name>android.hardware.usb</name>
- <transport>hwbinder</transport>
- <version>1.3</version>
+ <version>1</version>
<interface>
<name>IUsb</name>
<instance>default</instance>
</interface>
</hal>
</manifest>
-
diff --git a/usb/usb/service.cpp b/usb/usb/service.cpp
new file mode 100644
index 0000000..2c0a596
--- /dev/null
+++ b/usb/usb/service.cpp
@@ -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 <utils/Log.h>
+
+#include "Usb.h"
+
+using ::aidl::android::hardware::usb::Usb;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+ std::shared_ptr<Usb> usb = ndk::SharedRefBase::make<Usb>();
+
+ const std::string instance = std::string() + Usb::descriptor + "/default";
+ binder_status_t status = AServiceManager_addService(usb->asBinder().get(), instance.c_str());
+ CHECK(status == STATUS_OK);
+
+ ALOGV("AIDL USB HAL about to start");
+ ABinderProcess_joinThreadPool();
+ return -1; // Should never be reached
+}