summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-09 05:11:19 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-06-09 05:11:19 +0000
commite4f677303f0f85ad0debb5810b63a5f3955639b3 (patch)
treecc38afc91d20b917e2c0f474a44d70814286fdcf
parent3f93fab77ee6b6567358ef2aa1b7251bc7e7f433 (diff)
parent7ae80b6c132084fa62e7552edb8c1d32a66e139c (diff)
downloadredfin-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.mk5
-rw-r--r--usb/Usb.cpp840
-rw-r--r--usb/Usb.h103
-rw-r--r--usb/gadget/Android.bp (renamed from usb/Android.bp)13
-rw-r--r--usb/gadget/UsbGadget.cpp (renamed from usb/UsbGadget.cpp)0
-rw-r--r--usb/gadget/UsbGadget.h (renamed from usb/UsbGadget.h)0
-rw-r--r--usb/gadget/android.hardware.usb.gadget-service.redfin.rc (renamed from usb/android.hardware.usb@1.3-service.redfin.rc)2
-rw-r--r--usb/gadget/android.hardware.usb.gadget@1.1-service.redfin.xml (renamed from usb/android.hardware.usb.gadget@1.1-service.redfin.xml)0
-rw-r--r--usb/gadget/service_gadget.cpp (renamed from usb/service.cpp)22
-rw-r--r--usb/usb/Android.bp50
-rw-r--r--usb/usb/Usb.cpp876
-rw-r--r--usb/usb/Usb.h93
-rw-r--r--usb/usb/android.hardware.usb-service.rc12
-rw-r--r--usb/usb/android.hardware.usb-service.xml (renamed from usb/android.hardware.usb@1.3-service.redfin.xml)6
-rw-r--r--usb/usb/service.cpp37
15 files changed, 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, &currentPortStatus_1_2);
- return Void();
-}
-
-Return<void> Usb::enableContaminantPresenceProtection(const hidl_string & /*portName*/,
- bool /*enable*/) {
- hidl_vec<PortStatus> currentPortStatus_1_2;
-
- queryVersionHelper(this, &currentPortStatus_1_2);
- return Void();
-}
-
-std::string appendRoleNodeHelper(const std::string &portName, PortRoleType type) {
- std::string node("/sys/class/typec/" + portName);
-
- switch (type) {
- case PortRoleType::DATA_ROLE:
- return node + "/data_role";
- case PortRoleType::POWER_ROLE:
- return node + "/power_role";
- case PortRoleType::MODE:
- return node + "/port_type";
- default:
- return "";
- }
-}
-
-std::string convertRoletoString(PortRole role) {
- if (role.type == PortRoleType::POWER_ROLE) {
- if (role.role == static_cast<uint32_t>(PortPowerRole::SOURCE))
- return "source";
- else if (role.role == static_cast<uint32_t>(PortPowerRole::SINK))
- return "sink";
- } else if (role.type == PortRoleType::DATA_ROLE) {
- if (role.role == static_cast<uint32_t>(PortDataRole::HOST))
- return "host";
- if (role.role == static_cast<uint32_t>(PortDataRole::DEVICE))
- return "device";
- } else if (role.type == PortRoleType::MODE) {
- if (role.role == static_cast<uint32_t>(PortMode_1_1::UFP))
- return "sink";
- if (role.role == static_cast<uint32_t>(PortMode_1_1::DFP))
- return "source";
- }
- return "none";
-}
-
-void extractRole(std::string *roleName) {
- std::size_t first, last;
-
- first = roleName->find("[");
- last = roleName->find("]");
-
- if (first != std::string::npos && last != std::string::npos) {
- *roleName = roleName->substr(first + 1, last - first - 1);
- }
-}
-
-void switchToDrp(const std::string &portName) {
- std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), PortRoleType::MODE);
- FILE *fp;
-
- if (filename != "") {
- fp = fopen(filename.c_str(), "w");
- if (fp != NULL) {
- int ret = fputs("dual", fp);
- fclose(fp);
- if (ret == EOF)
- ALOGE("Fatal: Error while switching back to drp");
- } else {
- ALOGE("Fatal: Cannot open file to switch back to drp");
- }
- } else {
- ALOGE("Fatal: invalid node type");
- }
-}
-
-bool switchMode(const hidl_string &portName, const PortRole &newRole, struct Usb *usb) {
- std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
- std::string written;
- FILE *fp;
- bool roleSwitch = false;
-
- if (filename == "") {
- ALOGE("Fatal: invalid node type");
- return false;
- }
-
- fp = fopen(filename.c_str(), "w");
- if (fp != NULL) {
- // Hold the lock here to prevent loosing connected signals
- // as once the file is written the partner added signal
- // can arrive anytime.
- pthread_mutex_lock(&usb->mPartnerLock);
- usb->mPartnerUp = false;
- int ret = fputs(convertRoletoString(newRole).c_str(), fp);
- fclose(fp);
-
- if (ret != EOF) {
- struct timespec to;
- struct timespec now;
-
- wait_again:
- clock_gettime(CLOCK_MONOTONIC, &now);
- to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
- to.tv_nsec = now.tv_nsec;
-
- int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
- // There are no uevent signals which implies role swap timed out.
- if (err == ETIMEDOUT) {
- ALOGI("uevents wait timedout");
- // Sanity check.
- } else if (!usb->mPartnerUp) {
- goto wait_again;
- // Role switch succeeded since usb->mPartnerUp is true.
- } else {
- roleSwitch = true;
- }
- } else {
- ALOGI("Role switch failed while wrting to file");
- }
- pthread_mutex_unlock(&usb->mPartnerLock);
- }
-
- if (!roleSwitch)
- switchToDrp(std::string(portName.c_str()));
-
- return roleSwitch;
-}
-
-Usb::Usb()
- : mLock(PTHREAD_MUTEX_INITIALIZER),
- mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
- mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
- mPartnerUp(false) {
- pthread_condattr_t attr;
- if (pthread_condattr_init(&attr)) {
- ALOGE("pthread_condattr_init failed: %s", strerror(errno));
- abort();
- }
- if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
- ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
- abort();
- }
- if (pthread_cond_init(&mPartnerCV, &attr)) {
- ALOGE("pthread_cond_init failed: %s", strerror(errno));
- abort();
- }
- if (pthread_condattr_destroy(&attr)) {
- ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
- abort();
- }
-}
-
-Return<void> Usb::switchRole(const hidl_string &portName, const V1_0::PortRole &newRole) {
- std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
- std::string written;
- FILE *fp;
- bool roleSwitch = false;
-
- if (filename == "") {
- ALOGE("Fatal: invalid node type");
- return Void();
- }
-
- pthread_mutex_lock(&mRoleSwitchLock);
-
- ALOGI("filename write: %s role:%s", filename.c_str(), convertRoletoString(newRole).c_str());
-
- if (newRole.type == PortRoleType::MODE) {
- roleSwitch = switchMode(portName, newRole, this);
- } else {
- fp = fopen(filename.c_str(), "w");
- if (fp != NULL) {
- int ret = fputs(convertRoletoString(newRole).c_str(), fp);
- fclose(fp);
- if ((ret != EOF) && !readFile(filename, &written)) {
- extractRole(&written);
- ALOGI("written: %s", written.c_str());
- if (written == convertRoletoString(newRole)) {
- roleSwitch = true;
- } else {
- ALOGE("Role switch failed");
- }
- } else {
- ALOGE("failed to update the new role");
- }
- } else {
- ALOGE("fopen failed");
- }
- }
-
- pthread_mutex_lock(&mLock);
- if (mCallback_1_0 != NULL) {
- Return<void> ret = mCallback_1_0->notifyRoleSwitchStatus(
- portName, newRole, roleSwitch ? Status::SUCCESS : Status::ERROR);
- if (!ret.isOk())
- ALOGE("RoleSwitchStatus error %s", ret.description().c_str());
- } else {
- ALOGE("Not notifying the userspace. Callback is not set");
- }
- pthread_mutex_unlock(&mLock);
- pthread_mutex_unlock(&mRoleSwitchLock);
-
- return Void();
-}
-
-Status getAccessoryConnected(const std::string &portName, std::string *accessory) {
- std::string filename = "/sys/class/typec/" + portName + "-partner/accessory_mode";
-
- if (readFile(filename, accessory)) {
- ALOGE("getAccessoryConnected: Failed to open filesystem node: %s", filename.c_str());
- return Status::ERROR;
- }
-
- return Status::SUCCESS;
-}
-
-Status getCurrentRoleHelper(const std::string &portName, bool connected, PortRoleType type,
- uint32_t *currentRole) {
- std::string filename;
- std::string roleName;
- std::string accessory;
-
- // Mode
-
- if (type == PortRoleType::POWER_ROLE) {
- filename = "/sys/class/typec/" + portName + "/power_role";
- *currentRole = static_cast<uint32_t>(PortPowerRole::NONE);
- } else if (type == PortRoleType::DATA_ROLE) {
- filename = "/sys/class/typec/" + portName + "/data_role";
- *currentRole = static_cast<uint32_t>(PortDataRole::NONE);
- } else if (type == PortRoleType::MODE) {
- filename = "/sys/class/typec/" + portName + "/data_role";
- *currentRole = static_cast<uint32_t>(PortMode_1_1::NONE);
- } else {
- return Status::ERROR;
- }
-
- if (!connected)
- return Status::SUCCESS;
-
- if (type == PortRoleType::MODE) {
- if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
- return Status::ERROR;
- }
- if (accessory == "analog_audio") {
- *currentRole = static_cast<uint32_t>(PortMode_1_1::AUDIO_ACCESSORY);
- return Status::SUCCESS;
- } else if (accessory == "debug") {
- *currentRole = static_cast<uint32_t>(PortMode_1_1::DEBUG_ACCESSORY);
- return Status::SUCCESS;
- }
- }
-
- if (readFile(filename, &roleName)) {
- ALOGE("getCurrentRole: Failed to open filesystem node: %s", filename.c_str());
- return Status::ERROR;
- }
-
- extractRole(&roleName);
-
- if (roleName == "source") {
- *currentRole = static_cast<uint32_t>(PortPowerRole::SOURCE);
- } else if (roleName == "sink") {
- *currentRole = static_cast<uint32_t>(PortPowerRole::SINK);
- } else if (roleName == "host") {
- if (type == PortRoleType::DATA_ROLE)
- *currentRole = static_cast<uint32_t>(PortDataRole::HOST);
- else
- *currentRole = static_cast<uint32_t>(PortMode_1_1::DFP);
- } else if (roleName == "device") {
- if (type == PortRoleType::DATA_ROLE)
- *currentRole = static_cast<uint32_t>(PortDataRole::DEVICE);
- else
- *currentRole = static_cast<uint32_t>(PortMode_1_1::UFP);
- } else if (roleName != "none") {
- /* case for none has already been addressed.
- * so we check if the role isnt none.
- */
- return Status::UNRECOGNIZED_ROLE;
- }
-
- return Status::SUCCESS;
-}
-
-Status getTypeCPortNamesHelper(std::unordered_map<std::string, bool> *names) {
- DIR *dp;
-
- dp = opendir("/sys/class/typec");
- if (dp != NULL) {
- struct dirent *ep;
-
- while ((ep = readdir(dp))) {
- if (ep->d_type == DT_LNK) {
- if (std::string::npos == std::string(ep->d_name).find("-partner")) {
- std::unordered_map<std::string, bool>::const_iterator portName =
- names->find(ep->d_name);
- if (portName == names->end()) {
- names->insert({ep->d_name, false});
- }
- } else {
- (*names)[std::strtok(ep->d_name, "-")] = true;
- }
- }
- }
- closedir(dp);
- return Status::SUCCESS;
- }
-
- ALOGE("Failed to open /sys/class/typec");
- return Status::ERROR;
-}
-
-bool canSwitchRoleHelper(const std::string &portName, PortRoleType /*type*/) {
- std::string filename = "/sys/class/typec/" + portName + "-partner/supports_usb_power_delivery";
- std::string supportsPD;
-
- if (!readFile(filename, &supportsPD)) {
- if (supportsPD == "yes") {
- return true;
- }
- }
-
- return false;
-}
-
-/*
- * Reuse the same method for both V1_0 and V1_1 callback objects.
- * The caller of this method would reconstruct the V1_0::PortStatus
- * object if required.
- */
-Status getPortStatusHelper(hidl_vec<PortStatus> *currentPortStatus_1_2, HALVersion version) {
- std::unordered_map<std::string, bool> names;
- Status result = getTypeCPortNamesHelper(&names);
- int i = -1;
-
- if (result == Status::SUCCESS) {
- currentPortStatus_1_2->resize(names.size());
- for (std::pair<std::string, bool> port : names) {
- i++;
- ALOGI("%s", port.first.c_str());
- (*currentPortStatus_1_2)[i].status_1_1.status.portName = port.first;
-
- uint32_t currentRole;
- if (getCurrentRoleHelper(port.first, port.second, PortRoleType::POWER_ROLE,
- &currentRole) == Status::SUCCESS) {
- (*currentPortStatus_1_2)[i].status_1_1.status.currentPowerRole =
- static_cast<PortPowerRole>(currentRole);
- } else {
- ALOGE("Error while retreiving portNames");
- goto done;
- }
-
- if (getCurrentRoleHelper(port.first, port.second, PortRoleType::DATA_ROLE,
- &currentRole) == Status::SUCCESS) {
- (*currentPortStatus_1_2)[i].status_1_1.status.currentDataRole =
- static_cast<PortDataRole>(currentRole);
- } else {
- ALOGE("Error while retreiving current port role");
- goto done;
- }
-
- if (getCurrentRoleHelper(port.first, port.second, PortRoleType::MODE, &currentRole) ==
- Status::SUCCESS) {
- (*currentPortStatus_1_2)[i].status_1_1.currentMode =
- static_cast<PortMode_1_1>(currentRole);
- (*currentPortStatus_1_2)[i].status_1_1.status.currentMode =
- static_cast<V1_0::PortMode>(currentRole);
- } else {
- ALOGE("Error while retreiving current data role");
- goto done;
- }
-
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangeMode = true;
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangeDataRole =
- port.second ? canSwitchRoleHelper(port.first, PortRoleType::DATA_ROLE) : false;
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangePowerRole =
- port.second ? canSwitchRoleHelper(port.first, PortRoleType::POWER_ROLE) : false;
-
- if (version == HALVersion::V1_0) {
- ALOGI("HAL version V1_0");
- (*currentPortStatus_1_2)[i].status_1_1.status.supportedModes = V1_0::PortMode::DRP;
- } else {
- if (version == HALVersion::V1_1)
- ALOGI("HAL version V1_1");
- else
- ALOGI("HAL version V1_2");
- (*currentPortStatus_1_2)[i].status_1_1.supportedModes = 0 | PortMode_1_1::DRP;
- (*currentPortStatus_1_2)[i].status_1_1.status.supportedModes = V1_0::PortMode::NONE;
- (*currentPortStatus_1_2)[i].status_1_1.status.currentMode = V1_0::PortMode::NONE;
- }
-
- ALOGI(
- "%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
- "supportedModes:%d",
- i, port.first.c_str(), port.second,
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangeMode,
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangeDataRole,
- (*currentPortStatus_1_2)[i].status_1_1.status.canChangePowerRole,
- (*currentPortStatus_1_2)[i].status_1_1.supportedModes);
- }
- return Status::SUCCESS;
- }
-done:
- return Status::ERROR;
-}
-
-void queryVersionHelper(implementation::Usb *usb, hidl_vec<PortStatus> *currentPortStatus_1_2) {
- hidl_vec<V1_1::PortStatus_1_1> currentPortStatus_1_1;
- hidl_vec<V1_0::PortStatus> currentPortStatus;
- Status status;
- sp<V1_1::IUsbCallback> callback_V1_1 = V1_1::IUsbCallback::castFrom(usb->mCallback_1_0);
- sp<IUsbCallback> callback_V1_2 = IUsbCallback::castFrom(usb->mCallback_1_0);
-
- pthread_mutex_lock(&usb->mLock);
- if (usb->mCallback_1_0 != NULL) {
- if (callback_V1_2 != NULL) {
- status = getPortStatusHelper(currentPortStatus_1_2, HALVersion::V1_2);
- if (status == Status::SUCCESS)
- queryMoistureDetectionStatus(currentPortStatus_1_2);
- } else if (callback_V1_1 != NULL) {
- status = getPortStatusHelper(currentPortStatus_1_2, HALVersion::V1_1);
- currentPortStatus_1_1.resize(currentPortStatus_1_2->size());
- for (unsigned long i = 0; i < currentPortStatus_1_2->size(); i++)
- currentPortStatus_1_1[i] = (*currentPortStatus_1_2)[i].status_1_1;
- } else {
- status = getPortStatusHelper(currentPortStatus_1_2, HALVersion::V1_0);
- currentPortStatus.resize(currentPortStatus_1_2->size());
- for (unsigned long i = 0; i < currentPortStatus_1_2->size(); i++)
- currentPortStatus[i] = (*currentPortStatus_1_2)[i].status_1_1.status;
- }
-
- Return<void> ret;
-
- if (callback_V1_2 != NULL)
- ret = callback_V1_2->notifyPortStatusChange_1_2(*currentPortStatus_1_2, status);
- else if (callback_V1_1 != NULL)
- ret = callback_V1_1->notifyPortStatusChange_1_1(currentPortStatus_1_1, status);
- else
- ret = usb->mCallback_1_0->notifyPortStatusChange(currentPortStatus, status);
-
- if (!ret.isOk())
- ALOGE("queryPortStatus_1_2 error %s", ret.description().c_str());
- } else {
- ALOGI("Notifying userspace skipped. Callback is NULL");
- }
- pthread_mutex_unlock(&usb->mLock);
-}
-
-Return<void> Usb::queryPortStatus() {
- hidl_vec<PortStatus> currentPortStatus_1_2;
-
- queryVersionHelper(this, &currentPortStatus_1_2);
- return Void();
-}
-
-struct data {
- int uevent_fd;
- android::hardware::usb::V1_3::implementation::Usb *usb;
-};
-
-static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
- char msg[UEVENT_MSG_LEN + 2];
- char *cp;
- int n;
-
- n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
- if (n <= 0)
- return;
- if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
- return;
-
- msg[n] = '\0';
- msg[n + 1] = '\0';
- cp = msg;
-
- while (*cp) {
- if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
- ALOGI("partner added");
- pthread_mutex_lock(&payload->usb->mPartnerLock);
- payload->usb->mPartnerUp = true;
- pthread_cond_signal(&payload->usb->mPartnerCV);
- pthread_mutex_unlock(&payload->usb->mPartnerLock);
- } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_")) ||
- !strncmp(cp, "POWER_SUPPLY_MOISTURE_DETECTED",
- strlen("POWER_SUPPLY_MOISTURE_DETECTED"))) {
- hidl_vec<PortStatus> currentPortStatus_1_2;
- queryVersionHelper(payload->usb, &currentPortStatus_1_2);
-
- // Role switch is not in progress and port is in disconnected state
- if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
- for (unsigned long i = 0; i < currentPortStatus_1_2.size(); i++) {
- DIR *dp =
- opendir(std::string("/sys/class/typec/" +
- std::string(currentPortStatus_1_2[i]
- .status_1_1.status.portName.c_str()) +
- "-partner")
- .c_str());
- if (dp == NULL) {
- // PortRole role = {.role = static_cast<uint32_t>(PortMode::UFP)};
- switchToDrp(currentPortStatus_1_2[i].status_1_1.status.portName);
- } else {
- closedir(dp);
- }
- }
- pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
- }
- break;
- }
- /* advance to after the next \0 */
- while (*cp++) {
- }
- }
-}
-
-void *work(void *param) {
- int epoll_fd, uevent_fd;
- struct epoll_event ev;
- int nevents = 0;
- struct data payload;
-
- ALOGE("creating thread");
-
- uevent_fd = uevent_open_socket(64 * 1024, true);
-
- if (uevent_fd < 0) {
- ALOGE("uevent_init: uevent_open_socket failed\n");
- return NULL;
- }
-
- payload.uevent_fd = uevent_fd;
- payload.usb = (android::hardware::usb::V1_3::implementation::Usb *)param;
-
- fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
-
- ev.events = EPOLLIN;
- ev.data.ptr = (void *)uevent_event;
-
- epoll_fd = epoll_create(64);
- if (epoll_fd == -1) {
- ALOGE("epoll_create failed; errno=%d", errno);
- goto error;
- }
-
- if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
- ALOGE("epoll_ctl failed; errno=%d", errno);
- goto error;
- }
-
- while (!destroyThread) {
- struct epoll_event events[64];
-
- nevents = epoll_wait(epoll_fd, events, 64, -1);
- if (nevents == -1) {
- if (errno == EINTR)
- continue;
- ALOGE("usb epoll_wait failed; errno=%d", errno);
- break;
- }
-
- for (int n = 0; n < nevents; ++n) {
- if (events[n].data.ptr)
- (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events,
- &payload);
- }
- }
-
- ALOGI("exiting worker thread");
-error:
- close(uevent_fd);
-
- if (epoll_fd >= 0)
- close(epoll_fd);
-
- return NULL;
-}
-
-void sighandler(int sig) {
- if (sig == SIGUSR1) {
- destroyThread = true;
- ALOGI("destroy set");
- return;
- }
- signal(SIGUSR1, sighandler);
-}
-
-Return<void> Usb::setCallback(const sp<V1_0::IUsbCallback> &callback) {
- sp<V1_1::IUsbCallback> callback_V1_1 = V1_1::IUsbCallback::castFrom(callback);
- sp<IUsbCallback> callback_V1_2 = IUsbCallback::castFrom(callback);
-
- if (callback != NULL) {
- if (callback_V1_2 != NULL)
- ALOGI("Registering 1.2 callback");
- else if (callback_V1_1 != NULL)
- ALOGI("Registering 1.1 callback");
- }
-
- pthread_mutex_lock(&mLock);
- /*
- * When both the old callback and new callback values are NULL,
- * there is no need to spin off the worker thread.
- * When both the values are not NULL, we would already have a
- * worker thread running, so updating the callback object would
- * be suffice.
- */
- if ((mCallback_1_0 == NULL && callback == NULL) ||
- (mCallback_1_0 != NULL && callback != NULL)) {
- /*
- * Always store as V1_0 callback object. Type cast to V1_1
- * when the callback is actually invoked.
- */
- mCallback_1_0 = callback;
- pthread_mutex_unlock(&mLock);
- return Void();
- }
-
- mCallback_1_0 = callback;
- ALOGI("registering callback");
-
- // Kill the worker thread if the new callback is NULL.
- if (mCallback_1_0 == NULL) {
- pthread_mutex_unlock(&mLock);
- if (!pthread_kill(mPoll, SIGUSR1)) {
- pthread_join(mPoll, NULL);
- ALOGI("pthread destroyed");
- }
- return Void();
- }
-
- destroyThread = false;
- signal(SIGUSR1, sighandler);
-
- /*
- * Create a background thread if the old callback value is NULL
- * and being updated with a new value.
- */
- if (pthread_create(&mPoll, NULL, work, this)) {
- ALOGE("pthread creation failed %d", errno);
- mCallback_1_0 = NULL;
- }
-
- pthread_mutex_unlock(&mLock);
- return Void();
-}
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace usb
-} // namespace hardware
-} // namespace android
diff --git a/usb/Usb.h b/usb/Usb.h
deleted file mode 100644
index 5ff110d..0000000
--- a/usb/Usb.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <android-base/file.h>
-#include <android/hardware/usb/1.2/IUsbCallback.h>
-#include <android/hardware/usb/1.2/types.h>
-#include <android/hardware/usb/1.3/IUsb.h>
-#include <hidl/Status.h>
-#include <pixelusb/UsbGadgetCommon.h>
-#include <utils/Log.h>
-
-#define UEVENT_MSG_LEN 2048
-// The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd.
-// The -partner directory would not be created until this is done.
-// Having a margin of ~3 secs for the directory and other related bookeeping
-// structures created and uvent fired.
-#define PORT_TYPE_TIMEOUT 8
-
-namespace android {
-namespace hardware {
-namespace usb {
-namespace V1_3 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::base::WriteStringToFile;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::usb::V1_0::PortDataRole;
-using ::android::hardware::usb::V1_0::PortPowerRole;
-using ::android::hardware::usb::V1_0::PortRole;
-using ::android::hardware::usb::V1_0::PortRoleType;
-using ::android::hardware::usb::V1_0::Status;
-using ::android::hardware::usb::V1_1::PortMode_1_1;
-using ::android::hardware::usb::V1_1::PortStatus_1_1;
-using ::android::hardware::usb::V1_2::PortStatus;
-using ::android::hardware::usb::V1_2::IUsbCallback;
-using ::android::hardware::usb::V1_3::IUsb;
-using ::android::hidl::base::V1_0::DebugInfo;
-using ::android::hidl::base::V1_0::IBase;
-
-enum class HALVersion{
- V1_0,
- V1_1,
- V1_2,
- V1_3
-};
-
-constexpr char kGadgetName[] = "a600000.dwc3";
-#define SOC_PATH "/sys/devices/platform/soc/a600000.ssusb/"
-#define ID_PATH SOC_PATH "id"
-#define VBUS_PATH SOC_PATH "b_sess"
-#define USB_DATA_PATH SOC_PATH "usb_data_enabled"
-
-struct Usb : public IUsb {
- Usb();
-
- Return<void> switchRole(const hidl_string &portName, const V1_0::PortRole &role) override;
- Return<void> setCallback(const sp<V1_0::IUsbCallback> &callback) override;
- Return<void> queryPortStatus() override;
- Return<void> enableContaminantPresenceDetection(const hidl_string& portName, bool enable);
- Return<void> enableContaminantPresenceProtection(const hidl_string& portName, bool enable);
- Return<bool> enableUsbDataSignal(bool enable) override;
-
- sp<V1_0::IUsbCallback> mCallback_1_0;
- // Protects mCallback variable
- pthread_mutex_t mLock;
- // Protects roleSwitch operation
- pthread_mutex_t mRoleSwitchLock;
- // Threads waiting for the partner to come back wait here
- pthread_cond_t mPartnerCV;
- // lock protecting mPartnerCV
- pthread_mutex_t mPartnerLock;
- // Variable to signal partner coming back online after type switch
- bool mPartnerUp;
-
- private:
- pthread_t mPoll;
-};
-
-} // namespace implementation
-} // namespace V1_3
-} // namespace usb
-} // namespace hardware
-} // namespace android
diff --git a/usb/Android.bp b/usb/gadget/Android.bp
index 03b0c92..756b9eb 100644
--- a/usb/Android.bp
+++ b/usb/gadget/Android.bp
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2018 The Android Open Source Project
+// Copyright (C) 2021 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -18,19 +18,14 @@ package {
}
cc_binary {
- name: "android.hardware.usb@1.3-service.redfin",
+ name: "android.hardware.usb.gadget-service.redfin",
relative_install_path: "hw",
- init_rc: ["android.hardware.usb@1.3-service.redfin.rc"],
+ init_rc: ["android.hardware.usb.gadget-service.redfin.rc"],
vintf_fragments: [
- "android.hardware.usb@1.3-service.redfin.xml",
"android.hardware.usb.gadget@1.1-service.redfin.xml",
],
- srcs: ["service.cpp", "Usb.cpp", "UsbGadget.cpp"],
+ srcs: ["service_gadget.cpp", "UsbGadget.cpp"],
shared_libs: [
- "android.hardware.usb@1.0",
- "android.hardware.usb@1.1",
- "android.hardware.usb@1.2",
- "android.hardware.usb@1.3",
"android.hardware.usb.gadget@1.0",
"android.hardware.usb.gadget@1.1",
"libbase",
diff --git a/usb/UsbGadget.cpp b/usb/gadget/UsbGadget.cpp
index 97535f0..97535f0 100644
--- a/usb/UsbGadget.cpp
+++ b/usb/gadget/UsbGadget.cpp
diff --git a/usb/UsbGadget.h b/usb/gadget/UsbGadget.h
index 93c7d66..93c7d66 100644
--- a/usb/UsbGadget.h
+++ b/usb/gadget/UsbGadget.h
diff --git a/usb/android.hardware.usb@1.3-service.redfin.rc b/usb/gadget/android.hardware.usb.gadget-service.redfin.rc
index fffa93a..5e61e87 100644
--- a/usb/android.hardware.usb@1.3-service.redfin.rc
+++ b/usb/gadget/android.hardware.usb.gadget-service.redfin.rc
@@ -1,4 +1,4 @@
-service vendor.usb-hal-1-3 /vendor/bin/hw/android.hardware.usb@1.3-service.redfin
+service vendor.usb-gadget-hal-1-1 /vendor/bin/hw/android.hardware.usb.gadget-service.redfin
class hal
user system
group system shell mtp
diff --git a/usb/android.hardware.usb.gadget@1.1-service.redfin.xml b/usb/gadget/android.hardware.usb.gadget@1.1-service.redfin.xml
index a6f9a1f..a6f9a1f 100644
--- a/usb/android.hardware.usb.gadget@1.1-service.redfin.xml
+++ b/usb/gadget/android.hardware.usb.gadget@1.1-service.redfin.xml
diff --git a/usb/service.cpp b/usb/gadget/service_gadget.cpp
index 570beef..159e8f2 100644
--- a/usb/service.cpp
+++ b/usb/gadget/service_gadget.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,9 @@
* limitations under the License.
*/
-#define LOG_TAG "android.hardware.usb@1.3-service.redfin"
+#define LOG_TAG "android.hardware.usb.gadget-service.redfin"
#include <hidl/HidlTransportSupport.h>
-#include "Usb.h"
#include "UsbGadget.h"
using android::sp;
@@ -29,34 +28,23 @@ using android::hardware::joinRpcThreadpool;
// Generated HIDL files
using android::hardware::usb::gadget::V1_1::IUsbGadget;
using android::hardware::usb::gadget::V1_1::implementation::UsbGadget;
-using android::hardware::usb::V1_3::IUsb;
-using android::hardware::usb::V1_3::implementation::Usb;
using android::OK;
using android::status_t;
int main() {
- android::sp<IUsb> service = new Usb();
- android::sp<IUsbGadget> service2 = new UsbGadget();
-
+ android::sp<IUsbGadget> service = new UsbGadget();
configureRpcThreadpool(2, true /*callerWillJoin*/);
status_t status = service->registerAsService();
if (status != OK) {
- ALOGE("Cannot register USB HAL service");
- return 1;
- }
-
- status = service2->registerAsService();
-
- if (status != OK) {
ALOGE("Cannot register USB Gadget HAL service");
return 1;
}
- ALOGI("USB HAL Ready.");
+ ALOGI("USB gadget HAL Ready.");
joinRpcThreadpool();
// Under noraml cases, execution will not reach this line.
- ALOGI("USB HAL failed to join thread pool.");
+ ALOGI("USB gadget HAL failed to join thread pool.");
return 1;
}
diff --git a/usb/usb/Android.bp b/usb/usb/Android.bp
new file mode 100644
index 0000000..4f5d599
--- /dev/null
+++ b/usb/usb/Android.bp
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+ name: "android.hardware.usb-service.redfin",
+ relative_install_path: "hw",
+ init_rc: ["android.hardware.usb-service.rc"],
+ vintf_fragments: ["android.hardware.usb-service.xml"],
+ vendor: true,
+ srcs: [
+ "service.cpp",
+ "Usb.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "libhardware",
+ "android.hardware.usb.gadget@1.0",
+ "android.hardware.usb-V1-ndk",
+ "libcutils",
+ "android.frameworks.stats-V1-ndk",
+ "pixelatoms-cpp",
+ "libbinder_ndk",
+
+ ],
+ static_libs: [
+ "libpixelusb",
+ "libpixelstats",
+ ],
+ export_shared_lib_headers: [
+ "android.frameworks.stats-V1-ndk",
+ "pixelatoms-cpp",
+ ],
+}
diff --git a/usb/usb/Usb.cpp b/usb/usb/Usb.cpp
new file mode 100644
index 0000000..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, &currentPortStatus);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Usb::enableUsbDataWhileDocked(const string& in_portName,
+ int64_t in_transactionId) {
+ std::vector<PortStatus> currentPortStatus;
+
+ ALOGI("Userspace enableUsbDataWhileDocked opID:%ld", in_transactionId);
+
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ScopedAStatus ret = mCallback->notifyEnableUsbDataWhileDockedStatus(
+ in_portName, Status::NOT_SUPPORTED, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+ queryVersionHelper(this, &currentPortStatus);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Usb::resetUsbPort(const std::string& in_portName, int64_t in_transactionId) {
+ bool result = true;
+ std::vector<PortStatus> currentPortStatus;
+
+ ALOGI("Userspace reset USB Port. opID:%ld", in_transactionId);
+
+ if (!WriteStringToFile("none", PULLUP_PATH)) {
+ ALOGI("Gadget cannot be pulled down");
+ result = false;
+ }
+
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ::ndk::ScopedAStatus ret = mCallback->notifyResetUsbPortStatus(
+ in_portName, result ? Status::SUCCESS : Status::ERROR, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("notifyTransactionStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+
+ return ::ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus Usb::limitPowerTransfer(const string& in_portName, bool in_limit,
+ int64_t in_transactionId) {
+ std::vector<PortStatus> currentPortStatus;
+ 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, &currentPortStatus);
+
+ return ScopedAStatus::ok();
+}
+
+Status queryMoistureDetectionStatus(std::vector<PortStatus> *currentPortStatus) {
+ string enabled, status, path, DetectedPath;
+
+ (*currentPortStatus)[0].supportedContaminantProtectionModes
+ .push_back(ContaminantProtectionMode::FORCE_DISABLE);
+ (*currentPortStatus)[0].contaminantProtectionStatus = ContaminantProtectionStatus::NONE;
+ (*currentPortStatus)[0].contaminantDetectionStatus = ContaminantDetectionStatus::DISABLED;
+ (*currentPortStatus)[0].supportsEnableContaminantPresenceDetection = true;
+ (*currentPortStatus)[0].supportsEnableContaminantPresenceProtection = false;
+
+ if (!ReadFileToString(kEnabledPath, &enabled)) {
+ ALOGE("Failed to open moisture_detection_enabled");
+ return Status::ERROR;
+ }
+
+ enabled = Trim(enabled);
+ if (enabled == "1") {
+ if (!ReadFileToString(kDetectedPath, &status)) {
+ ALOGE("Failed to open moisture_detected");
+ return Status::ERROR;
+ }
+ status = Trim(status);
+ if (status == "1") {
+ (*currentPortStatus)[0].contaminantDetectionStatus =
+ ContaminantDetectionStatus::DETECTED;
+ (*currentPortStatus)[0].contaminantProtectionStatus =
+ ContaminantProtectionStatus::FORCE_DISABLE;
+ } else {
+ (*currentPortStatus)[0].contaminantDetectionStatus =
+ ContaminantDetectionStatus::NOT_DETECTED;
+ }
+ }
+
+ ALOGI("ContaminantDetectionStatus:%d ContaminantProtectionStatus:%d",
+ (*currentPortStatus)[0].contaminantDetectionStatus,
+ (*currentPortStatus)[0].contaminantProtectionStatus);
+
+ return Status::SUCCESS;
+}
+
+string appendRoleNodeHelper(const string &portName, PortRole::Tag tag) {
+ string node("/sys/class/typec/" + portName);
+
+ switch (tag) {
+ case PortRole::dataRole:
+ return node + "/data_role";
+ case PortRole::powerRole:
+ return node + "/power_role";
+ case PortRole::mode:
+ return node + "/port_type";
+ default:
+ return "";
+ }
+}
+
+string convertRoletoString(PortRole role) {
+ if (role.getTag() == PortRole::powerRole) {
+ if (role.get<PortRole::powerRole>() == PortPowerRole::SOURCE)
+ return "source";
+ else if (role.get<PortRole::powerRole>() == PortPowerRole::SINK)
+ return "sink";
+ } else if (role.getTag() == PortRole::dataRole) {
+ if (role.get<PortRole::dataRole>() == PortDataRole::HOST)
+ return "host";
+ if (role.get<PortRole::dataRole>() == PortDataRole::DEVICE)
+ return "device";
+ } else if (role.getTag() == PortRole::mode) {
+ if (role.get<PortRole::mode>() == PortMode::UFP)
+ return "sink";
+ if (role.get<PortRole::mode>() == PortMode::DFP)
+ return "source";
+ }
+ return "none";
+}
+
+void extractRole(string *roleName) {
+ std::size_t first, last;
+
+ first = roleName->find("[");
+ last = roleName->find("]");
+
+ if (first != string::npos && last != string::npos) {
+ *roleName = roleName->substr(first + 1, last - first - 1);
+ }
+}
+
+void switchToDrp(const string &portName) {
+ string filename = appendRoleNodeHelper(string(portName.c_str()), PortRole::mode);
+ FILE *fp;
+
+ if (filename != "") {
+ fp = fopen(filename.c_str(), "w");
+ if (fp != NULL) {
+ int ret = fputs("dual", fp);
+ fclose(fp);
+ if (ret == EOF)
+ ALOGE("Fatal: Error while switching back to drp");
+ } else {
+ ALOGE("Fatal: Cannot open file to switch back to drp");
+ }
+ } else {
+ ALOGE("Fatal: invalid node type");
+ }
+}
+
+bool switchMode(const string &portName, const PortRole &in_role, struct Usb *usb) {
+ string filename = appendRoleNodeHelper(string(portName.c_str()), in_role.getTag());
+ string written;
+ FILE *fp;
+ bool roleSwitch = false;
+
+ if (filename == "") {
+ ALOGE("Fatal: invalid node type");
+ return false;
+ }
+
+ fp = fopen(filename.c_str(), "w");
+ if (fp != NULL) {
+ // Hold the lock here to prevent loosing connected signals
+ // as once the file is written the partner added signal
+ // can arrive anytime.
+ pthread_mutex_lock(&usb->mPartnerLock);
+ usb->mPartnerUp = false;
+ int ret = fputs(convertRoletoString(in_role).c_str(), fp);
+ fclose(fp);
+
+ if (ret != EOF) {
+ struct timespec to;
+ struct timespec now;
+
+ wait_again:
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
+ to.tv_nsec = now.tv_nsec;
+
+ int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
+ // There are no uevent signals which implies role swap timed out.
+ if (err == ETIMEDOUT) {
+ ALOGI("uevents wait timedout");
+ // Validity check.
+ } else if (!usb->mPartnerUp) {
+ goto wait_again;
+ // Role switch succeeded since usb->mPartnerUp is true.
+ } else {
+ roleSwitch = true;
+ }
+ } else {
+ ALOGI("Role switch failed while wrting to file");
+ }
+ pthread_mutex_unlock(&usb->mPartnerLock);
+ }
+
+ if (!roleSwitch)
+ switchToDrp(string(portName.c_str()));
+
+ return roleSwitch;
+}
+
+Usb::Usb()
+ : mLock(PTHREAD_MUTEX_INITIALIZER),
+ mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
+ mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
+ mPartnerUp(false),
+ 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, &currentRole) == Status::SUCCESS){
+ (*currentPortStatus)[i].currentPowerRole = currentRole.get<PortRole::powerRole>();
+ } else {
+ ALOGE("Error while retrieving portNames");
+ goto done;
+ }
+
+ currentRole.set<PortRole::dataRole>(PortDataRole::NONE);
+ if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
+ (*currentPortStatus)[i].currentDataRole = currentRole.get<PortRole::dataRole>();
+ } else {
+ ALOGE("Error while retrieving current port role");
+ goto done;
+ }
+
+ currentRole.set<PortRole::mode>(PortMode::NONE);
+ if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
+ (*currentPortStatus)[i].currentMode = currentRole.get<PortRole::mode>();
+ } else {
+ ALOGE("Error while retrieving current data role");
+ goto done;
+ }
+
+ (*currentPortStatus)[i].canChangeMode = true;
+ (*currentPortStatus)[i].canChangeDataRole =
+ port.second ? canSwitchRoleHelper(port.first) : false;
+ (*currentPortStatus)[i].canChangePowerRole =
+ port.second ? canSwitchRoleHelper(port.first) : false;
+
+ (*currentPortStatus)[i].supportedModes.push_back(PortMode::DRP);
+
+ if (!usb->mUsbDataEnabled) {
+ (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::DISABLED_FORCE);
+ } else {
+ (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::ENABLED);
+ }
+ (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::UNKNOWN;
+
+ ALOGI("%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
+ "usbDataEnabled:%d",
+ i, port.first.c_str(), port.second,
+ (*currentPortStatus)[i].canChangeMode,
+ (*currentPortStatus)[i].canChangeDataRole,
+ (*currentPortStatus)[i].canChangePowerRole,
+ usb->mUsbDataEnabled ? 1 : 0);
+ }
+ return Status::SUCCESS;
+ }
+done:
+ return Status::ERROR;
+}
+
+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, &currentPortStatus);
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ScopedAStatus ret = mCallback->notifyQueryPortStatus(
+ "all", Status::SUCCESS, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("notifyQueryPortStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Usb::enableContaminantPresenceDetection(const string& in_portName,
+ bool in_enable, int64_t in_transactionId) {
+ string disable = GetProperty(kDisableContatminantDetection, "");
+ std::string status = GetProperty(kConsole, "");
+ std::vector<PortStatus> currentPortStatus;
+ bool success = true;
+
+ if (status != "running" && disable != "true")
+ success = WriteStringToFile(in_enable ? "1" : "0", kEnabledPath);
+
+ pthread_mutex_lock(&mLock);
+ if (mCallback != NULL) {
+ ScopedAStatus ret = mCallback->notifyContaminantEnabledStatus(
+ in_portName, in_enable, success ? Status::SUCCESS : Status::ERROR, in_transactionId);
+ if (!ret.isOk())
+ ALOGE("notifyContaminantEnabledStatus error %s", ret.getDescription().c_str());
+ } else {
+ ALOGE("Not notifying the userspace. Callback is not set");
+ }
+ pthread_mutex_unlock(&mLock);
+
+ queryVersionHelper(this, &currentPortStatus);
+ return ScopedAStatus::ok();
+}
+
+struct data {
+ int uevent_fd;
+ ::aidl::android::hardware::usb::Usb *usb;
+};
+
+static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
+ char msg[UEVENT_MSG_LEN + 2];
+ char *cp;
+ int n;
+
+ n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
+ if (n <= 0)
+ return;
+ if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
+ return;
+
+ msg[n] = '\0';
+ msg[n + 1] = '\0';
+ cp = msg;
+
+ while (*cp) {
+ if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
+ ALOGI("partner added");
+ pthread_mutex_lock(&payload->usb->mPartnerLock);
+ payload->usb->mPartnerUp = true;
+ pthread_cond_signal(&payload->usb->mPartnerCV);
+ pthread_mutex_unlock(&payload->usb->mPartnerLock);
+ } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_")) ||
+ !strncmp(cp, "POWER_SUPPLY_MOISTURE_DETECTED",
+ strlen("POWER_SUPPLY_MOISTURE_DETECTED"))) {
+ std::vector<PortStatus> currentPortStatus;
+ queryVersionHelper(payload->usb, &currentPortStatus);
+
+ // Role switch is not in progress and port is in disconnected state
+ if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
+ for (unsigned long i = 0; i < currentPortStatus.size(); i++) {
+ DIR *dp =
+ opendir(string("/sys/class/typec/" +
+ string(currentPortStatus[i].portName.c_str()) +
+ "-partner").c_str());
+ if (dp == NULL) {
+ switchToDrp(currentPortStatus[i].portName);
+ } else {
+ closedir(dp);
+ }
+ }
+ pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
+ }
+ break;
+ }
+ /* advance to after the next \0 */
+ while (*cp++) {
+ }
+ }
+}
+
+void *work(void *param) {
+ int epoll_fd, uevent_fd;
+ struct epoll_event ev;
+ int nevents = 0;
+ struct data payload;
+
+ ALOGE("creating thread");
+
+ uevent_fd = uevent_open_socket(64 * 1024, true);
+
+ if (uevent_fd < 0) {
+ ALOGE("uevent_init: uevent_open_socket failed\n");
+ return NULL;
+ }
+
+ payload.uevent_fd = uevent_fd;
+ payload.usb = (::aidl::android::hardware::usb::Usb *)param;
+
+ fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
+
+ ev.events = EPOLLIN;
+ ev.data.ptr = (void *)uevent_event;
+
+ epoll_fd = epoll_create(64);
+ if (epoll_fd == -1) {
+ ALOGE("epoll_create failed; errno=%d", errno);
+ goto error;
+ }
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
+ ALOGE("epoll_ctl failed; errno=%d", errno);
+ goto error;
+ }
+
+ while (!destroyThread) {
+ struct epoll_event events[64];
+
+ nevents = epoll_wait(epoll_fd, events, 64, -1);
+ if (nevents == -1) {
+ if (errno == EINTR)
+ continue;
+ ALOGE("usb epoll_wait failed; errno=%d", errno);
+ break;
+ }
+
+ for (int n = 0; n < nevents; ++n) {
+ if (events[n].data.ptr)
+ (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events,
+ &payload);
+ }
+ }
+
+ ALOGI("exiting worker thread");
+error:
+ close(uevent_fd);
+
+ if (epoll_fd >= 0)
+ close(epoll_fd);
+
+ return NULL;
+}
+
+void sighandler(int sig) {
+ if (sig == SIGUSR1) {
+ destroyThread = true;
+ ALOGI("destroy set");
+ return;
+ }
+ signal(SIGUSR1, sighandler);
+}
+
+ScopedAStatus Usb::setCallback(const shared_ptr<IUsbCallback>& in_callback) {
+ pthread_mutex_lock(&mLock);
+ if ((mCallback == NULL && in_callback == NULL) ||
+ (mCallback != NULL && in_callback != NULL)) {
+ mCallback = in_callback;
+ pthread_mutex_unlock(&mLock);
+ return ScopedAStatus::ok();
+ }
+
+ mCallback = in_callback;
+ ALOGI("registering callback");
+
+ if (mCallback == NULL) {
+ if (!pthread_kill(mPoll, SIGUSR1)) {
+ pthread_join(mPoll, NULL);
+ ALOGI("pthread destroyed");
+ }
+ pthread_mutex_unlock(&mLock);
+ return ScopedAStatus::ok();
+ }
+
+ destroyThread = false;
+ signal(SIGUSR1, sighandler);
+
+ /*
+ * Create a background thread if the old callback value is NULL
+ * and being updated with a new value.
+ */
+ if (pthread_create(&mPoll, NULL, work, this)) {
+ ALOGE("pthread creation failed %d", errno);
+ mCallback = NULL;
+ }
+
+ pthread_mutex_unlock(&mLock);
+ return ScopedAStatus::ok();
+}
+
+} // namespace usb
+} // namespace hardware
+} // namespace android
+} // aidl
diff --git a/usb/usb/Usb.h b/usb/usb/Usb.h
new file mode 100644
index 0000000..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
+}