diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-09 05:11:19 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-06-09 05:11:19 +0000 |
commit | e4f677303f0f85ad0debb5810b63a5f3955639b3 (patch) | |
tree | cc38afc91d20b917e2c0f474a44d70814286fdcf | |
parent | 3f93fab77ee6b6567358ef2aa1b7251bc7e7f433 (diff) | |
parent | 7ae80b6c132084fa62e7552edb8c1d32a66e139c (diff) | |
download | redfin-android13-mainline-appsearch-release.tar.gz |
Snap for 8701376 from 7ae80b6c132084fa62e7552edb8c1d32a66e139c to mainline-appsearch-releaseaml_ase_331311020aml_ase_331112000aml_ase_331011020android13-mainline-appsearch-release
Change-Id: Ie46783567e865a2e29d3e7ce60e2ff0744038529
-rw-r--r-- | device-redfin.mk | 5 | ||||
-rw-r--r-- | usb/Usb.cpp | 840 | ||||
-rw-r--r-- | usb/Usb.h | 103 | ||||
-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.bp | 50 | ||||
-rw-r--r-- | usb/usb/Usb.cpp | 876 | ||||
-rw-r--r-- | usb/usb/Usb.h | 93 | ||||
-rw-r--r-- | usb/usb/android.hardware.usb-service.rc | 12 | ||||
-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.cpp | 37 |
15 files changed, 1084 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, ¤tPortStatus_1_2); - return Void(); -} - -Return<void> Usb::enableContaminantPresenceProtection(const hidl_string & /*portName*/, - bool /*enable*/) { - hidl_vec<PortStatus> currentPortStatus_1_2; - - queryVersionHelper(this, ¤tPortStatus_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, - ¤tRole) == 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, - ¤tRole) == 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, ¤tRole) == - 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, ¤tPortStatus_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, ¤tPortStatus_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..ed358cd --- /dev/null +++ b/usb/usb/Usb.cpp @@ -0,0 +1,876 @@ +/* + * 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; + string pullup; + + ALOGI("Userspace turn %s USB data signaling. opID:%ld", in_enable ? "on" : "off", + in_transactionId); + + if (in_enable) { + if (ReadFileToString(PULLUP_PATH, &pullup)) { + pullup = Trim(pullup); + if (pullup != kGadgetName) { + if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) { + ALOGE("Gadget cannot be pulled up"); + result = false; + } + } + } + + if (!WriteStringToFile("1", USB_DATA_PATH)) { + ALOGE("Not able to turn on usb connection notification"); + result = false; + } + } else { + if (ReadFileToString(PULLUP_PATH, &pullup)) { + pullup = Trim(pullup); + if (pullup == kGadgetName) { + if (!WriteStringToFile("none", PULLUP_PATH)) { + ALOGE("Gadget cannot be pulled down"); + result = false; + } + } + } + + if (!WriteStringToFile("0", USB_DATA_PATH)) { + ALOGE("Not able to turn on usb connection notification"); + 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, ¤tPortStatus); + + 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, ¤tPortStatus); + + 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; + bool sessionFail = false, success; + + pthread_mutex_lock(&mLock); + ALOGI("limitPowerTransfer limit:%c opId:%ld", in_limit ? 'y' : 'n', in_transactionId); + + if (in_limit) { + success = WriteStringToFile("0", SINK_CURRENT_LIMIT_PATH); + if (!success) { + ALOGE("Failed to set sink current limit"); + sessionFail = true; + } + } + success = WriteStringToFile(in_limit ? "1" : "0", SINK_LIMIT_ENABLE_PATH); + if (!success) { + ALOGE("Failed to %s sink current limit: %s", in_limit ? "enable" : "disable", + SINK_LIMIT_ENABLE_PATH); + sessionFail = true; + } + success = WriteStringToFile(in_limit ? "1" : "0", SOURCE_LIMIT_ENABLE_PATH); + if (!success) { + ALOGE("Failed to %s source current limit: %s", in_limit ? "enable" : "disable", + SOURCE_LIMIT_ENABLE_PATH); + sessionFail = true; + } + + if (mCallback != NULL && in_transactionId >= 0) { + ScopedAStatus ret = mCallback->notifyLimitPowerTransferStatus( + in_portName, in_limit, sessionFail ? Status::ERROR : Status::SUCCESS, + 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, ¤tPortStatus); + + 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), + mUsbDataEnabled(true) { + 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, ¤tRole) == 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, ¤tRole) == 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, ¤tRole) == 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; +} + +Status queryPowerTransferStatus(std::vector<PortStatus> *currentPortStatus) { + string enabled; + + if (!ReadFileToString(SINK_LIMIT_ENABLE_PATH, &enabled)) { + ALOGE("Failed to open limit_sink_enable"); + return Status::ERROR; + } + + enabled = Trim(enabled); + (*currentPortStatus)[0].powerTransferLimited = enabled == "1"; + + ALOGI("powerTransferLimited:%d", (*currentPortStatus)[0].powerTransferLimited ? 1 : 0); + return Status::SUCCESS; +} + +void queryVersionHelper(android::hardware::usb::Usb *usb, + std::vector<PortStatus> *currentPortStatus) { + Status status; + pthread_mutex_lock(&usb->mLock); + status = getPortStatusHelper(usb, currentPortStatus); + queryMoistureDetectionStatus(currentPortStatus); + queryPowerTransferStatus(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, ¤tPortStatus); + 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, ¤tPortStatus); + 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, ¤tPortStatus); + + // 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..36a23bc --- /dev/null +++ b/usb/usb/Usb.h @@ -0,0 +1,93 @@ +/* + * 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 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 USB_POWER_LIMIT_PATH "/sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm7250b@2:qcom,usb-pdphy@1700/usbpd0/" +#define SINK_CURRENT_LIMIT_PATH USB_POWER_LIMIT_PATH "usb_limit_sink_current" +#define SINK_LIMIT_ENABLE_PATH USB_POWER_LIMIT_PATH "usb_limit_sink_enable" +#define SOURCE_LIMIT_ENABLE_PATH USB_POWER_LIMIT_PATH "usb_limit_source_enable" + +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..2801dd4 --- /dev/null +++ b/usb/usb/android.hardware.usb-service.rc @@ -0,0 +1,12 @@ +service vendor.usb /vendor/bin/hw/android.hardware.usb-service.redfin + class hal + user system + group system shell + +on boot + chown root system /sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm7250b@2:qcom,usb-pdphy@1700/usbpd0/usb_limit_sink_enable + chown root system /sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm7250b@2:qcom,usb-pdphy@1700/usbpd0/usb_limit_source_enable + chown root system /sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm7250b@2:qcom,usb-pdphy@1700/usbpd0/usb_limit_sink_current + chmod 664 /sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm7250b@2:qcom,usb-pdphy@1700/usbpd0/usb_limit_sink_enable + chmod 664 /sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm7250b@2:qcom,usb-pdphy@1700/usbpd0/usb_limit_source_enable + chmod 664 /sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm7250b@2:qcom,usb-pdphy@1700/usbpd0/usb_limit_sink_current 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 +} |