From 71543928efa30f6eb7042448a62afdcb65eec7f0 Mon Sep 17 00:00:00 2001 From: Ocean Chen Date: Thu, 13 Jan 2022 17:17:49 +0000 Subject: [PATCH 1/3] Pixelstats: add more UFS error count paths The UFS resume flow also increase the reset count. It makes the reset count cannot represent the real error count. So we use other count instead of reset count Bug: 199459367 Change-Id: I0249d806351a1037f7886368d4df1d22af4c0091 --- pixelstats/service.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/pixelstats/service.cpp b/pixelstats/service.cpp index 4201207b..a265bac6 100644 --- a/pixelstats/service.cpp +++ b/pixelstats/service.cpp @@ -26,6 +26,7 @@ using android::hardware::google::pixel::SysfsCollector; using android::hardware::google::pixel::UeventListener; #define UFSHC_PATH(filename) "/dev/sys/block/bootdevice/" #filename +#define UFS_ERR_PATH(err_type) UFSHC_PATH(err_stats/) #err_type const struct SysfsCollector::SysfsPaths sysfs_paths = { .SlowioReadCntPath = UFSHC_PATH(slowio_read_cnt), .SlowioWriteCntPath = UFSHC_PATH(slowio_write_cnt), @@ -35,12 +36,21 @@ const struct SysfsCollector::SysfsPaths sysfs_paths = { .UFSLifetimeA = UFSHC_PATH(health_descriptor/life_time_estimation_a), .UFSLifetimeB = UFSHC_PATH(health_descriptor/life_time_estimation_b), .UFSLifetimeC = UFSHC_PATH(health_descriptor/life_time_estimation_c), - .UFSHostResetPath = UFSHC_PATH(err_stats/dev_reset_count), .F2fsStatsPath = "/sys/fs/f2fs/", .ImpedancePath = "/sys/devices/platform/audiometrics/speaker_impedance", .CodecPath = "/sys/devices/platform/audiometrics/codec_state", .EEPROMPath = "/dev/battery_history", - .MitigationPath = "/sys/devices/virtual/pmic/mitigation"}; + .MitigationPath = "/sys/devices/virtual/pmic/mitigation", + .UFSErrStatsPath = { + UFS_ERR_PATH(pa_err_count), + UFS_ERR_PATH(dl_err_count), + UFS_ERR_PATH(nl_err_count), + UFS_ERR_PATH(tl_err_count), + UFS_ERR_PATH(dme_err_count), + UFS_ERR_PATH(fatal_err_count), + UFS_ERR_PATH(auto_hibern8_err_count) + } +}; const struct UeventListener::UeventPaths ueventPaths = { .AudioUevent = "/devices/virtual/amcs/amcs", .WirelessChargerPtmcPath = "/sys/class/power_supply/wireless/device/ptmc_id"}; From 3c97a6bb68f6418ee41026f3bd0024405c97cf0c Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Mon, 17 Jan 2022 20:43:02 -0800 Subject: [PATCH 2/3] 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. Bug: 200993386 Bug: 199357330 Change-Id: I02753af4a41916b77ce110f9531504bf8c6a4691 --- device.mk | 4 +- usb/Usb.cpp | 938 ------------------ usb/{ => gadget}/Android.bp | 23 +- usb/{ => gadget}/UsbGadget.cpp | 0 usb/{ => gadget}/UsbGadget.h | 0 ...roid.hardware.usb.gadget-service.gs101.rc} | 2 +- ....hardware.usb.gadget@1.2-service.gs101.xml | 0 .../service_gadget.cpp} | 22 +- usb/usb/Android.bp | 52 + usb/usb/Usb.cpp | 850 ++++++++++++++++ usb/{ => usb}/Usb.h | 74 +- usb/usb/android.hardware.usb-service.rc | 21 + .../android.hardware.usb-service.xml} | 6 +- usb/usb/service.cpp | 37 + 14 files changed, 1001 insertions(+), 1028 deletions(-) delete mode 100644 usb/Usb.cpp rename usb/{ => gadget}/Android.bp (67%) rename usb/{ => gadget}/UsbGadget.cpp (100%) rename usb/{ => gadget}/UsbGadget.h (100%) rename usb/{android.hardware.usb@1.3-service.gs101.rc => gadget/android.hardware.usb.gadget-service.gs101.rc} (98%) rename usb/{ => gadget}/android.hardware.usb.gadget@1.2-service.gs101.xml (100%) rename usb/{service.cpp => gadget/service_gadget.cpp} (70%) create mode 100644 usb/usb/Android.bp create mode 100644 usb/usb/Usb.cpp rename usb/{ => usb}/Usb.h (54%) create mode 100644 usb/usb/android.hardware.usb-service.rc rename usb/{android.hardware.usb@1.3-service.gs101.xml => usb/android.hardware.usb-service.xml} (69%) create mode 100644 usb/usb/service.cpp diff --git a/device.mk b/device.mk index 8759aa69..b1855c16 100644 --- a/device.mk +++ b/device.mk @@ -394,7 +394,9 @@ endif # USB HAL PRODUCT_PACKAGES += \ - android.hardware.usb@1.3-service.gs101 + android.hardware.usb-service.gs101 +PRODUCT_PACKAGES += \ + android.hardware.usb.gadget-service.gs101 # MIDI feature PRODUCT_COPY_FILES += \ diff --git a/usb/Usb.cpp b/usb/Usb.cpp deleted file mode 100644 index caf4f57b..00000000 --- a/usb/Usb.cpp +++ /dev/null @@ -1,938 +0,0 @@ -/* - * Copyright (C) 2020 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.gs101" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "Usb.h" -#include "UsbGadget.h" - -#include -#include - -using aidl::android::frameworks::stats::IStats; -using android::base::GetProperty; -using android::hardware::google::pixel::getStatsService; -using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat; -using android::hardware::google::pixel::reportUsbPortOverheat; - -namespace android { -namespace hardware { -namespace usb { -namespace V1_3 { -namespace implementation { - -Return 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 off 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; - -std::string enabledPath; -constexpr char kHsi2cPath[] = "/sys/devices/platform/10d50000.hsi2c"; -constexpr char kI2CPath[] = "/sys/devices/platform/10d50000.hsi2c/i2c-"; -constexpr char kContaminantDetectionPath[] = "i2c-max77759tcpc/contaminant_detection"; -constexpr char kStatusPath[] = "i2c-max77759tcpc/contaminant_detection_status"; -constexpr char kTypecPath[] = "/sys/class/typec"; -constexpr char kDisableContatminantDetection[] = "vendor.usb.contaminantdisable"; -constexpr char kOverheatStatsPath[] = "/sys/devices/platform/google,usbc_port_cooling_dev/"; -constexpr char kOverheatStatsDev[] = "DRIVER=google,usbc_port_cooling_dev"; -constexpr char kThermalZoneForTrip[] = "VIRTUAL-USB-THROTTLING"; -constexpr char kThermalZoneForTempReadPrimary[] = "usb_pwr_therm2"; -constexpr char kThermalZoneForTempReadSecondary1[] = "usb_pwr_therm"; -constexpr char kThermalZoneForTempReadSecondary2[] = "qi_therm"; -constexpr int kSamplingIntervalSec = 5; - -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 getContaminantDetectionNamesHelper(std::string *name) { - DIR *dp; - - dp = opendir(kHsi2cPath); - if (dp != NULL) { - struct dirent *ep; - - while ((ep = readdir(dp))) { - if (ep->d_type == DT_DIR) { - if (std::string::npos != std::string(ep->d_name).find("i2c-")) { - std::strtok(ep->d_name, "-"); - *name = std::strtok(NULL, "-"); - } - } - } - closedir(dp); - return Status::SUCCESS; - } - - ALOGE("Failed to open %s", kHsi2cPath); - return Status::ERROR; -} - -Status queryMoistureDetectionStatus(hidl_vec *currentPortStatus_1_2) { - std::string enabled, status, path, DetectedPath; - - 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; - - getContaminantDetectionNamesHelper(&path); - enabledPath = kI2CPath + path + "/" + kContaminantDetectionPath; - if (readFile(enabledPath, &enabled)) { - ALOGE("Failed to open moisture_detection_enabled"); - return Status::ERROR; - } - - if (enabled == "1") { - DetectedPath = kI2CPath + path + "/" + kStatusPath; - if (readFile(DetectedPath, &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; -} - -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(PortPowerRole::SOURCE)) - return "source"; - else if (role.role == static_cast(PortPowerRole::SINK)) - return "sink"; - } else if (role.type == PortRoleType::DATA_ROLE) { - if (role.role == static_cast(PortDataRole::HOST)) - return "host"; - if (role.role == static_cast(PortDataRole::DEVICE)) - return "device"; - } else if (role.type == PortRoleType::MODE) { - if (role.role == static_cast(PortMode_1_1::UFP)) - return "sink"; - if (role.role == static_cast(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"); - // 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(std::string(portName.c_str())); - - return roleSwitch; -} - -Usb::Usb() - : mLock(PTHREAD_MUTEX_INITIALIZER), - mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER), - mPartnerLock(PTHREAD_MUTEX_INITIALIZER), - mPartnerUp(false), - mOverheat(ZoneInfo(TemperatureType::USB_PORT, kThermalZoneForTrip, - ThrottlingSeverity::CRITICAL), - {ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadPrimary, - ThrottlingSeverity::NONE), - ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary1, - ThrottlingSeverity::NONE), - ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary2, - ThrottlingSeverity::NONE)}, kSamplingIntervalSec) { - 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 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 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(PortPowerRole::NONE); - } else if (type == PortRoleType::DATA_ROLE) { - filename = "/sys/class/typec/" + portName + "/data_role"; - *currentRole = static_cast(PortDataRole::NONE); - } else if (type == PortRoleType::MODE) { - filename = "/sys/class/typec/" + portName + "/data_role"; - *currentRole = static_cast(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(PortMode_1_1::AUDIO_ACCESSORY); - return Status::SUCCESS; - } else if (accessory == "debug") { - *currentRole = static_cast(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(PortPowerRole::SOURCE); - } else if (roleName == "sink") { - *currentRole = static_cast(PortPowerRole::SINK); - } else if (roleName == "host") { - if (type == PortRoleType::DATA_ROLE) - *currentRole = static_cast(PortDataRole::HOST); - else - *currentRole = static_cast(PortMode_1_1::DFP); - } else if (roleName == "device") { - if (type == PortRoleType::DATA_ROLE) - *currentRole = static_cast(PortDataRole::DEVICE); - else - *currentRole = static_cast(PortMode_1_1::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 *names) { - DIR *dp; - - dp = opendir(kTypecPath); - 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::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 *currentPortStatus_1_2, HALVersion version, - android::hardware::usb::V1_3::implementation::Usb *usb) { - std::unordered_map names; - Status result = getTypeCPortNamesHelper(&names); - int i = -1; - - if (result == Status::SUCCESS) { - currentPortStatus_1_2->resize(names.size()); - for (std::pair 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(currentRole); - } else { - ALOGE("Error while retrieving 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(currentRole); - } else { - ALOGE("Error while retrieving 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(currentRole); - (*currentPortStatus_1_2)[i].status_1_1.status.currentMode = - static_cast(currentRole); - } else { - ALOGE("Error while retrieving 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; - } - - // Query temperature for the first connect - if (port.second && !usb->mPluggedTemperatureCelsius) { - usb->mOverheat.getCurrentTemperature(kThermalZoneForTempReadPrimary, - &usb->mPluggedTemperatureCelsius); - ALOGV("USB Initial temperature: %f", usb->mPluggedTemperatureCelsius); - } - 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(android::hardware::usb::V1_3::implementation::Usb *usb, - hidl_vec *currentPortStatus_1_2) { - hidl_vec currentPortStatus_1_1; - hidl_vec currentPortStatus; - Status status; - sp callback_V1_1 = V1_1::IUsbCallback::castFrom(usb->mCallback_1_0); - sp 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, usb); - if (status == Status::SUCCESS) - queryMoistureDetectionStatus(currentPortStatus_1_2); - } else if (callback_V1_1 != NULL) { - status = getPortStatusHelper(currentPortStatus_1_2, HALVersion::V1_1, usb); - 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, usb); - 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 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 Usb::queryPortStatus() { - hidl_vec currentPortStatus_1_2; - - queryVersionHelper(this, ¤tPortStatus_1_2); - return Void(); -} - -Return Usb::enableContaminantPresenceDetection(const hidl_string & /*portName*/, - bool enable) { - - std::string disable = GetProperty(kDisableContatminantDetection, ""); - - if (disable != "true") - writeFile(enabledPath, enable ? "1" : "0"); - - hidl_vec currentPortStatus_1_2; - - queryVersionHelper(this, ¤tPortStatus_1_2); - return Void(); -} - -Return Usb::enableContaminantPresenceProtection(const hidl_string & /*portName*/, - bool /*enable*/) { - hidl_vec currentPortStatus_1_2; - - queryVersionHelper(this, ¤tPortStatus_1_2); - return Void(); -} - -void report_overheat_event(android::hardware::usb::V1_3::implementation::Usb *usb) { - VendorUsbPortOverheat overheat_info; - std::string contents; - - overheat_info.set_plug_temperature_deci_c(usb->mPluggedTemperatureCelsius * 10); - overheat_info.set_max_temperature_deci_c(usb->mOverheat.getMaxOverheatTemperature() * 10); - if (ReadFileToString(std::string(kOverheatStatsPath) + "trip_time", &contents)) { - overheat_info.set_time_to_overheat_secs(stoi(contents)); - } else { - ALOGE("Unable to read trip_time"); - return; - } - if (ReadFileToString(std::string(kOverheatStatsPath) + "hysteresis_time", &contents)) { - overheat_info.set_time_to_hysteresis_secs(stoi(contents)); - } else { - ALOGE("Unable to read hysteresis_time"); - return; - } - if (ReadFileToString(std::string(kOverheatStatsPath) + "cleared_time", &contents)) { - overheat_info.set_time_to_inactive_secs(stoi(contents)); - } else { - ALOGE("Unable to read cleared_time"); - return; - } - - const std::shared_ptr stats_client = getStatsService(); - if (!stats_client) { - ALOGE("Unable to get AIDL Stats service"); - } else { - reportUsbPortOverheat(stats_client, overheat_info); - } -} - -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); - // Update Plugged temperature - payload->usb->mOverheat.getCurrentTemperature(kThermalZoneForTempReadPrimary, - &payload->usb->mPluggedTemperatureCelsius); - ALOGI("Usb Plugged temp: %f", payload->usb->mPluggedTemperatureCelsius); - } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_")) || - !strncmp(cp, "DRIVER=max77759tcpc", - strlen("DRIVER=max77759tcpc"))) { - hidl_vec 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(PortMode::UFP)}; - switchToDrp(currentPortStatus_1_2[i].status_1_1.status.portName); - } else { - closedir(dp); - } - } - pthread_mutex_unlock(&payload->usb->mRoleSwitchLock); - } - break; - } else if (!strncmp(cp, kOverheatStatsDev, strlen(kOverheatStatsDev))) { - ALOGV("Overheat Cooling device suez update"); - report_overheat_event(payload->usb); - } - /* 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 Usb::setCallback(const sp &callback) { - sp callback_V1_1 = V1_1::IUsbCallback::castFrom(callback); - sp 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/Android.bp b/usb/gadget/Android.bp similarity index 67% rename from usb/Android.bp rename to usb/gadget/Android.bp index 5aafe145..ab7ac325 100644 --- a/usb/Android.bp +++ b/usb/gadget/Android.bp @@ -1,5 +1,5 @@ // -// Copyright (C) 2017 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. @@ -25,14 +25,13 @@ package { } cc_binary { - name: "android.hardware.usb@1.3-service.gs101", + name: "android.hardware.usb.gadget-service.gs101", relative_install_path: "hw", - init_rc: ["android.hardware.usb@1.3-service.gs101.rc"], + init_rc: ["android.hardware.usb.gadget-service.gs101.rc"], vintf_fragments: [ - "android.hardware.usb@1.3-service.gs101.xml", "android.hardware.usb.gadget@1.2-service.gs101.xml", ], - srcs: ["service.cpp", "Usb.cpp", "UsbGadget.cpp"], + srcs: ["service_gadget.cpp", "UsbGadget.cpp"], cflags: ["-Wall", "-Werror"], shared_libs: [ "libbase", @@ -41,27 +40,13 @@ cc_binary { "liblog", "libutils", "libhardware", - "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", "android.hardware.usb.gadget@1.2", - "android.hardware.thermal@1.0", - "android.hardware.thermal@2.0", "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", ], proprietary: true, } diff --git a/usb/UsbGadget.cpp b/usb/gadget/UsbGadget.cpp similarity index 100% rename from usb/UsbGadget.cpp rename to usb/gadget/UsbGadget.cpp diff --git a/usb/UsbGadget.h b/usb/gadget/UsbGadget.h similarity index 100% rename from usb/UsbGadget.h rename to usb/gadget/UsbGadget.h diff --git a/usb/android.hardware.usb@1.3-service.gs101.rc b/usb/gadget/android.hardware.usb.gadget-service.gs101.rc similarity index 98% rename from usb/android.hardware.usb@1.3-service.gs101.rc rename to usb/gadget/android.hardware.usb.gadget-service.gs101.rc index 4112b4ec..dcf44bb9 100644 --- a/usb/android.hardware.usb@1.3-service.gs101.rc +++ b/usb/gadget/android.hardware.usb.gadget-service.gs101.rc @@ -1,4 +1,4 @@ -service vendor.usb-hal-1-3 /vendor/bin/hw/android.hardware.usb@1.3-service.gs101 +service vendor.usb-gadget-hal-1-2 /vendor/bin/hw/android.hardware.usb.gadget-service.gs101 class hal user system group system shell mtp wakelock diff --git a/usb/android.hardware.usb.gadget@1.2-service.gs101.xml b/usb/gadget/android.hardware.usb.gadget@1.2-service.gs101.xml similarity index 100% rename from usb/android.hardware.usb.gadget@1.2-service.gs101.xml rename to usb/gadget/android.hardware.usb.gadget@1.2-service.gs101.xml diff --git a/usb/service.cpp b/usb/gadget/service_gadget.cpp similarity index 70% rename from usb/service.cpp rename to usb/gadget/service_gadget.cpp index a4a30d2a..d0908ee4 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) 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. @@ -14,10 +14,9 @@ * limitations under the License. */ -#define LOG_TAG "android.hardware.usb@1.3-service.gs101" +#define LOG_TAG "android.hardware.usb.gadget-service.gs101" #include -#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_2::IUsbGadget; using android::hardware::usb::gadget::V1_2::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 service = new Usb(); - android::sp service2 = new UsbGadget(); - + android::sp 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 00000000..0ce3167a --- /dev/null +++ b/usb/usb/Android.bp @@ -0,0 +1,52 @@ +// +// 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.gs101", + 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.thermal@1.0", + "android.hardware.thermal@2.0", + "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 00000000..7aa4ced0 --- /dev/null +++ b/usb/usb/Usb.cpp @@ -0,0 +1,850 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "Usb.h" + +#include +#include +#include + +using aidl::android::frameworks::stats::IStats; +using android::base::GetProperty; +using android::base::Trim; +using android::hardware::google::pixel::getStatsService; +using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat; +using android::hardware::google::pixel::reportUsbPortOverheat; + +namespace aidl { +namespace android { +namespace hardware { +namespace usb { +// Set by the signal handler to destroy the thread +volatile bool destroyThread; + +string enabledPath; +constexpr char kHsi2cPath[] = "/sys/devices/platform/10d50000.hsi2c"; +constexpr char kI2CPath[] = "/sys/devices/platform/10d50000.hsi2c/i2c-"; +constexpr char kContaminantDetectionPath[] = "i2c-max77759tcpc/contaminant_detection"; +constexpr char kStatusPath[] = "i2c-max77759tcpc/contaminant_detection_status"; +constexpr char kTypecPath[] = "/sys/class/typec"; +constexpr char kDisableContatminantDetection[] = "vendor.usb.contaminantdisable"; +constexpr char kOverheatStatsPath[] = "/sys/devices/platform/google,usbc_port_cooling_dev/"; +constexpr char kOverheatStatsDev[] = "DRIVER=google,usbc_port_cooling_dev"; +constexpr char kThermalZoneForTrip[] = "VIRTUAL-USB-THROTTLING"; +constexpr char kThermalZoneForTempReadPrimary[] = "usb_pwr_therm2"; +constexpr char kThermalZoneForTempReadSecondary1[] = "usb_pwr_therm"; +constexpr char kThermalZoneForTempReadSecondary2[] = "qi_therm"; +constexpr int kSamplingIntervalSec = 5; +void queryVersionHelper(android::hardware::usb::Usb *usb, + std::vector *currentPortStatus); + +ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable, + int64_t in_transactionId) { + bool result = true; + std::vector 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, ¤tPortStatus); + + return ScopedAStatus::ok(); +} + +Status getContaminantDetectionNamesHelper(string *name) { + DIR *dp; + + dp = opendir(kHsi2cPath); + if (dp != NULL) { + struct dirent *ep; + + while ((ep = readdir(dp))) { + if (ep->d_type == DT_DIR) { + if (string::npos != string(ep->d_name).find("i2c-")) { + std::strtok(ep->d_name, "-"); + *name = std::strtok(NULL, "-"); + } + } + } + closedir(dp); + return Status::SUCCESS; + } + + ALOGE("Failed to open %s", kHsi2cPath); + return Status::ERROR; +} + +Status queryMoistureDetectionStatus(std::vector *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; + + getContaminantDetectionNamesHelper(&path); + enabledPath = kI2CPath + path + "/" + kContaminantDetectionPath; + if (!ReadFileToString(enabledPath, &enabled)) { + ALOGE("Failed to open moisture_detection_enabled"); + return Status::ERROR; + } + + enabled = Trim(enabled); + if (enabled == "1") { + DetectedPath = kI2CPath + path + "/" + kStatusPath; + if (!ReadFileToString(DetectedPath, &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() == PortPowerRole::SOURCE) + return "source"; + else if (role.get() == PortPowerRole::SINK) + return "sink"; + } else if (role.getTag() == PortRole::dataRole) { + if (role.get() == PortDataRole::HOST) + return "host"; + if (role.get() == PortDataRole::DEVICE) + return "device"; + } else if (role.getTag() == PortRole::mode) { + if (role.get() == PortMode::UFP) + return "sink"; + if (role.get() == 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), + mOverheat(ZoneInfo(TemperatureType::USB_PORT, kThermalZoneForTrip, + ThrottlingSeverity::CRITICAL), + {ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadPrimary, + ThrottlingSeverity::NONE), + ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary1, + ThrottlingSeverity::NONE), + ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary2, + ThrottlingSeverity::NONE)}, kSamplingIntervalSec), + 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; + + // Mode + + if (currentRole->getTag() == PortRole::powerRole) { + filename = "/sys/class/typec/" + portName + "/power_role"; + currentRole->set(PortPowerRole::NONE); + } else if (currentRole->getTag() == PortRole::dataRole) { + filename = "/sys/class/typec/" + portName + "/data_role"; + currentRole->set(PortDataRole::NONE); + } else if (currentRole->getTag() == PortRole::mode) { + filename = "/sys/class/typec/" + portName + "/data_role"; + currentRole->set(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(PortMode::AUDIO_ACCESSORY); + return Status::SUCCESS; + } else if (accessory == "debug") { + currentRole->set(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(PortPowerRole::SOURCE); + } else if (roleName == "sink") { + currentRole->set(PortPowerRole::SINK); + } else if (roleName == "host") { + if (currentRole->getTag() == PortRole::dataRole) + currentRole->set(PortDataRole::HOST); + else + currentRole->set(PortMode::DFP); + } else if (roleName == "device") { + if (currentRole->getTag() == PortRole::dataRole) + currentRole->set(PortDataRole::DEVICE); + else + currentRole->set(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 *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::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 *currentPortStatus) { + std::unordered_map names; + Status result = getTypeCPortNamesHelper(&names); + int i = -1; + + if (result == Status::SUCCESS) { + currentPortStatus->resize(names.size()); + for (std::pair port : names) { + i++; + ALOGI("%s", port.first.c_str()); + (*currentPortStatus)[i].portName = port.first; + + PortRole currentRole; + currentRole.set(PortPowerRole::NONE); + if (getCurrentRoleHelper(port.first, port.second, ¤tRole) == Status::SUCCESS){ + (*currentPortStatus)[i].currentPowerRole = currentRole.get(); + } else { + ALOGE("Error while retrieving portNames"); + goto done; + } + + currentRole.set(PortDataRole::NONE); + if (getCurrentRoleHelper(port.first, port.second, ¤tRole) == Status::SUCCESS) { + (*currentPortStatus)[i].currentDataRole = currentRole.get(); + } else { + ALOGE("Error while retrieving current port role"); + goto done; + } + + currentRole.set(PortMode::NONE); + if (getCurrentRoleHelper(port.first, port.second, ¤tRole) == Status::SUCCESS) { + (*currentPortStatus)[i].currentMode = currentRole.get(); + } 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); + (*currentPortStatus)[i].usbDataEnabled = usb->mUsbDataEnabled; + + 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, + (*currentPortStatus)[i].usbDataEnabled ? 1 : 0); + } + return Status::SUCCESS; + } +done: + return Status::ERROR; +} + +void queryVersionHelper(android::hardware::usb::Usb *usb, + std::vector *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 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::vector currentPortStatus; + bool success = true; + + if (disable != "true") + success = WriteStringToFile(in_enable ? "1" : "0", enabledPath); + + 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(); +} + + +void report_overheat_event(android::hardware::usb::Usb *usb) { + VendorUsbPortOverheat overheat_info; + string contents; + + overheat_info.set_plug_temperature_deci_c(usb->mPluggedTemperatureCelsius * 10); + overheat_info.set_max_temperature_deci_c(usb->mOverheat.getMaxOverheatTemperature() * 10); + if (ReadFileToString(string(kOverheatStatsPath) + "trip_time", &contents)) { + overheat_info.set_time_to_overheat_secs(stoi(Trim(contents))); + } else { + ALOGE("Unable to read trip_time"); + return; + } + if (ReadFileToString(string(kOverheatStatsPath) + "hysteresis_time", &contents)) { + overheat_info.set_time_to_hysteresis_secs(stoi(Trim(contents))); + } else { + ALOGE("Unable to read hysteresis_time"); + return; + } + if (ReadFileToString(string(kOverheatStatsPath) + "cleared_time", &contents)) { + overheat_info.set_time_to_inactive_secs(stoi(Trim(contents))); + } else { + ALOGE("Unable to read cleared_time"); + return; + } + + const shared_ptr stats_client = getStatsService(); + if (!stats_client) { + ALOGE("Unable to get AIDL Stats service"); + } else { + reportUsbPortOverheat(stats_client, overheat_info); + } +} + +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, "DRIVER=max77759tcpc", + strlen("DRIVER=max77759tcpc"))) { + std::vector 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; + } else if (!strncmp(cp, kOverheatStatsDev, strlen(kOverheatStatsDev))) { + ALOGV("Overheat Cooling device suez update"); + report_overheat_event(payload->usb); + } + /* 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& 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.h b/usb/usb/Usb.h similarity index 54% rename from usb/Usb.h rename to usb/usb/Usb.h index 23ed0111..51f9d439 100644 --- a/usb/Usb.h +++ b/usb/usb/Usb.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 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. @@ -17,10 +17,8 @@ #pragma once #include -#include -#include -#include -#include +#include +#include #include #include @@ -31,46 +29,23 @@ // structures created and uvent fired. #define PORT_TYPE_TIMEOUT 8 +namespace aidl { namespace android { namespace hardware { namespace usb { -namespace V1_3 { -namespace implementation { -using ::android::base::WriteStringToFile; +using ::aidl::android::hardware::usb::IUsbCallback; +using ::aidl::android::hardware::usb::PortRole; using ::android::base::ReadFileToString; -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::base::WriteStringToFile; using ::android::hardware::google::pixel::usb::UsbOverheatEvent; using ::android::hardware::google::pixel::usb::ZoneInfo; using ::android::hardware::thermal::V2_0::TemperatureType; using ::android::hardware::thermal::V2_0::ThrottlingSeverity; -using ::android::hardware::usb::V1_0::PortRole; -using ::android::hardware::usb::V1_0::PortRoleType; -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_3::IUsb; -using ::android::hardware::usb::V1_2::IUsbCallback; -using ::android::hardware::usb::V1_2::PortStatus; -using ::android::hardware::usb::V1_1::PortMode_1_1; -using ::android::hardware::usb::V1_1::PortStatus_1_1; -using ::android::hidl::base::V1_0::DebugInfo; -using ::android::hidl::base::V1_0::IBase; using ::android::sp; - -enum class HALVersion{ - V1_0, - V1_1, - V1_2, - V1_3 -}; +using ::ndk::ScopedAStatus; +using ::std::shared_ptr; +using ::std::string; constexpr char kGadgetName[] = "11110000.dwc3"; #define NEW_UDC_PATH "/sys/devices/platform/11110000.usb/" @@ -79,17 +54,19 @@ constexpr char kGadgetName[] = "11110000.dwc3"; #define VBUS_PATH NEW_UDC_PATH "dwc3_exynos_otg_b_sess" #define USB_DATA_PATH NEW_UDC_PATH "usb_data_enabled" -struct Usb : public IUsb { +struct Usb : public BnUsb { Usb(); - Return switchRole(const hidl_string &portName, const PortRole &role) override; - Return setCallback(const sp& callback) override; - Return queryPortStatus() override; - Return enableContaminantPresenceDetection(const hidl_string &portName, bool enable); - Return enableContaminantPresenceProtection(const hidl_string &portName, bool enable); - Return enableUsbDataSignal(bool enable) override; + 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& 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; - sp mCallback_1_0; + std::shared_ptr<::aidl::android::hardware::usb::IUsbCallback> mCallback; // Protects mCallback variable pthread_mutex_t mLock; // Protects roleSwitch operation @@ -105,13 +82,14 @@ struct Usb : public IUsb { UsbOverheatEvent mOverheat; // Temperature when connected float mPluggedTemperatureCelsius; + // Usb Data status + bool mUsbDataEnabled; private: pthread_t mPoll; }; -} // namespace implementation -} // namespace V1_3 -} // namespace usb -} // namespace hardware -} // namespace android +} // 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 00000000..c842877b --- /dev/null +++ b/usb/usb/android.hardware.usb-service.rc @@ -0,0 +1,21 @@ +service vendor.usb /vendor/bin/hw/android.hardware.usb-service.gs101 + class hal + user system + group system shell wakelock + capabilities WAKE_ALARM BLOCK_SUSPEND + +on post-fs + chown root system /sys/class/typec/port0/power_role + chown root system /sys/class/typec/port0/data_role + chown root system /sys/class/typec/port0/port_type + chown root system /sys/devices/platform/10d50000.hsi2c/i2c-5/i2c-max77759tcpc/contaminant_detection + chown root system /sys/devices/platform/10d50000.hsi2c/i2c-6/i2c-max77759tcpc/contaminant_detection + chown root system /sys/devices/platform/11110000.usb/dwc3_exynos_otg_b_sess + chown root system /sys/devices/platform/11110000.usb/dwc3_exynos_otg_id + chown root system /sys/devices/platform/11110000.usb/usb_data_enabled + chmod 664 /sys/class/typec/port0/power_role + chmod 664 /sys/class/typec/port0/data_role + chmod 664 /sys/class/typec/port0/port_type + chmod 664 /sys/devices/platform/11110000.usb/dwc3_exynos_otg_b_sess + chmod 664 /sys/devices/platform/11110000.usb/dwc3_exynos_otg_id + chmod 664 /sys/devices/platform/11110000.usb/usb_data_enabled diff --git a/usb/android.hardware.usb@1.3-service.gs101.xml b/usb/usb/android.hardware.usb-service.xml similarity index 69% rename from usb/android.hardware.usb@1.3-service.gs101.xml rename to usb/usb/android.hardware.usb-service.xml index cd542687..60881948 100644 --- a/usb/android.hardware.usb@1.3-service.gs101.xml +++ b/usb/usb/android.hardware.usb-service.xml @@ -1,12 +1,10 @@ - + android.hardware.usb - hwbinder - 1.3 + 1 IUsb default - diff --git a/usb/usb/service.cpp b/usb/usb/service.cpp new file mode 100644 index 00000000..2c0a5963 --- /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 +#include +#include +#include + +#include "Usb.h" + +using ::aidl::android::hardware::usb::Usb; + +int main() { + ABinderProcess_setThreadPoolMaxThreadCount(0); + std::shared_ptr usb = ndk::SharedRefBase::make(); + + 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 +} From 9a5124a117f24667f234719b35fbc60238ed0fa1 Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Thu, 25 Nov 2021 09:52:34 -0800 Subject: [PATCH 3/3] Implement callbacks for limitPowerTransfer Implements limiting the sink current current when limitPowerTransfer is invoked. Bug: 199357330 Signed-off-by: Badhri Jagan Sridharan Change-Id: I751a3912ebd159a536808897f878502418c6efdb --- usb/usb/Usb.cpp | 65 +++++++++++++++++++++++-- usb/usb/Usb.h | 3 +- usb/usb/android.hardware.usb-service.rc | 10 ++++ 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/usb/usb/Usb.cpp b/usb/usb/Usb.cpp index 7aa4ced0..8115ce27 100644 --- a/usb/usb/Usb.cpp +++ b/usb/usb/Usb.cpp @@ -60,6 +60,8 @@ constexpr char kHsi2cPath[] = "/sys/devices/platform/10d50000.hsi2c"; constexpr char kI2CPath[] = "/sys/devices/platform/10d50000.hsi2c/i2c-"; constexpr char kContaminantDetectionPath[] = "i2c-max77759tcpc/contaminant_detection"; constexpr char kStatusPath[] = "i2c-max77759tcpc/contaminant_detection_status"; +constexpr char kSinkLimitEnable[] = "i2c-max77759tcpc/usb_limit_sink_enable"; +constexpr char kSinkLimitCurrent[] = "i2c-max77759tcpc/usb_limit_sink_current"; constexpr char kTypecPath[] = "/sys/class/typec"; constexpr char kDisableContatminantDetection[] = "vendor.usb.contaminantdisable"; constexpr char kOverheatStatsPath[] = "/sys/devices/platform/google,usbc_port_cooling_dev/"; @@ -130,7 +132,7 @@ ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable, return ScopedAStatus::ok(); } -Status getContaminantDetectionNamesHelper(string *name) { +Status getI2cBusHelper(string *name) { DIR *dp; dp = opendir(kHsi2cPath); @@ -163,7 +165,7 @@ Status queryMoistureDetectionStatus(std::vector *currentPortStatus) (*currentPortStatus)[0].supportsEnableContaminantPresenceDetection = true; (*currentPortStatus)[0].supportsEnableContaminantPresenceProtection = false; - getContaminantDetectionNamesHelper(&path); + getI2cBusHelper(&path); enabledPath = kI2CPath + path + "/" + kContaminantDetectionPath; if (!ReadFileToString(enabledPath, &enabled)) { ALOGE("Failed to open moisture_detection_enabled"); @@ -402,6 +404,61 @@ ScopedAStatus Usb::switchRole(const string& in_portName, const PortRole& in_role return ScopedAStatus::ok(); } +ScopedAStatus Usb::limitPowerTransfer(const string& in_portName, bool in_limit, + int64_t in_transactionId) { + bool success = false; + std::vector currentPortStatus; + string path, limitEnablePath, currentLimitPath; + + getI2cBusHelper(&path); + limitEnablePath = kI2CPath + path + "/" + kSinkLimitEnable; + currentLimitPath = kI2CPath + path + "/" + kSinkLimitCurrent; + + if (in_limit) { + success = WriteStringToFile("0", currentLimitPath); + if (!success) { + ALOGE("Failed to set sink current limit"); + } + } + success = WriteStringToFile(in_limit ? "1" : "0", limitEnablePath); + if (!success) { + ALOGE("Failed to %s sink current limit: %s", in_limit ? "enable" : "disable", + limitEnablePath.c_str()); + } + 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, success ? Status::SUCCESS : Status::ERROR, 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 queryPowerTransferStatus(std::vector *currentPortStatus) { + string limitedPath, enabled, path; + + getI2cBusHelper(&path); + limitedPath = kI2CPath + path + "/" + kSinkLimitEnable; + if (!ReadFileToString(limitedPath, &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; +} + Status getAccessoryConnected(const string &portName, string *accessory) { string filename = "/sys/class/typec/" + portName + "-partner/accessory_mode"; @@ -571,13 +628,14 @@ Status getPortStatusHelper(android::hardware::usb::Usb *usb, (*currentPortStatus)[i].usbDataEnabled = usb->mUsbDataEnabled; ALOGI("%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d " - "usbDataEnabled:%d", + "usbDataEnabled:%d", i, port.first.c_str(), port.second, (*currentPortStatus)[i].canChangeMode, (*currentPortStatus)[i].canChangeDataRole, (*currentPortStatus)[i].canChangePowerRole, (*currentPortStatus)[i].usbDataEnabled ? 1 : 0); } + return Status::SUCCESS; } done: @@ -590,6 +648,7 @@ void queryVersionHelper(android::hardware::usb::Usb *usb, pthread_mutex_lock(&usb->mLock); status = getPortStatusHelper(usb, currentPortStatus); queryMoistureDetectionStatus(currentPortStatus); + queryPowerTransferStatus(currentPortStatus); if (usb->mCallback != NULL) { ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus, status); diff --git a/usb/usb/Usb.h b/usb/usb/Usb.h index 51f9d439..a361f84b 100644 --- a/usb/usb/Usb.h +++ b/usb/usb/Usb.h @@ -65,6 +65,8 @@ struct Usb : public BnUsb { int64_t in_transactionId) override; ScopedAStatus enableUsbData(const string& in_portName, bool in_enable, int64_t in_transactionId) override; + ScopedAStatus limitPowerTransfer(const string& in_portName, bool in_limit, + int64_t in_transactionId) override; std::shared_ptr<::aidl::android::hardware::usb::IUsbCallback> mCallback; // Protects mCallback variable @@ -84,7 +86,6 @@ struct Usb : public BnUsb { float mPluggedTemperatureCelsius; // Usb Data status bool mUsbDataEnabled; - private: pthread_t mPoll; }; diff --git a/usb/usb/android.hardware.usb-service.rc b/usb/usb/android.hardware.usb-service.rc index c842877b..e79a672c 100644 --- a/usb/usb/android.hardware.usb-service.rc +++ b/usb/usb/android.hardware.usb-service.rc @@ -10,6 +10,10 @@ on post-fs chown root system /sys/class/typec/port0/port_type chown root system /sys/devices/platform/10d50000.hsi2c/i2c-5/i2c-max77759tcpc/contaminant_detection chown root system /sys/devices/platform/10d50000.hsi2c/i2c-6/i2c-max77759tcpc/contaminant_detection + chown root system /sys/devices/platform/10d50000.hsi2c/i2c-5/i2c-max77759tcpc/usb_limit_sink_current + chown root system /sys/devices/platform/10d50000.hsi2c/i2c-6/i2c-max77759tcpc/usb_limit_sink_current + chown root system /sys/devices/platform/10d50000.hsi2c/i2c-5/i2c-max77759tcpc/usb_limit_sink_enable + chown root system /sys/devices/platform/10d50000.hsi2c/i2c-6/i2c-max77759tcpc/usb_limit_sink_enable chown root system /sys/devices/platform/11110000.usb/dwc3_exynos_otg_b_sess chown root system /sys/devices/platform/11110000.usb/dwc3_exynos_otg_id chown root system /sys/devices/platform/11110000.usb/usb_data_enabled @@ -19,3 +23,9 @@ on post-fs chmod 664 /sys/devices/platform/11110000.usb/dwc3_exynos_otg_b_sess chmod 664 /sys/devices/platform/11110000.usb/dwc3_exynos_otg_id chmod 664 /sys/devices/platform/11110000.usb/usb_data_enabled + chmod 664 /sys/devices/platform/10d50000.hsi2c/i2c-5/i2c-max77759tcpc/contaminant_detection + chmod 664 /sys/devices/platform/10d50000.hsi2c/i2c-6/i2c-max77759tcpc/contaminant_detection + chmod 664 /sys/devices/platform/10d50000.hsi2c/i2c-5/i2c-max77759tcpc/usb_limit_sink_current + chmod 664 /sys/devices/platform/10d50000.hsi2c/i2c-6/i2c-max77759tcpc/usb_limit_sink_current + chmod 664 /sys/devices/platform/10d50000.hsi2c/i2c-5/i2c-max77759tcpc/usb_limit_sink_enable + chmod 664 /sys/devices/platform/10d50000.hsi2c/i2c-6/i2c-max77759tcpc/usb_limit_sink_enable