Home | History | Annotate | Download | only in usb
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "android.hardware.usb (at) 1.1-service.wahoo"
     18 
     19 #include <android-base/logging.h>
     20 #include <assert.h>
     21 #include <chrono>
     22 #include <dirent.h>
     23 #include <pthread.h>
     24 #include <regex>
     25 #include <stdio.h>
     26 #include <sys/types.h>
     27 #include <thread>
     28 #include <unistd.h>
     29 #include <unordered_map>
     30 
     31 #include <cutils/uevent.h>
     32 #include <sys/epoll.h>
     33 #include <utils/Errors.h>
     34 #include <utils/StrongPointer.h>
     35 
     36 #include "Usb.h"
     37 
     38 namespace android {
     39 namespace hardware {
     40 namespace usb {
     41 namespace V1_1 {
     42 namespace implementation {
     43 
     44 const char GOOGLE_USB_VENDOR_ID_STR[] = "18d1";
     45 const char GOOGLE_USBC_35_ADAPTER_UNPLUGGED_ID_STR[] = "5029";
     46 
     47 // Set by the signal handler to destroy the thread
     48 volatile bool destroyThread;
     49 
     50 static void checkUsbDeviceAutoSuspend(const std::string& devicePath);
     51 
     52 static int32_t readFile(const std::string &filename, std::string *contents) {
     53   FILE *fp;
     54   ssize_t read = 0;
     55   char *line = NULL;
     56   size_t len = 0;
     57 
     58   fp = fopen(filename.c_str(), "r");
     59   if (fp != NULL) {
     60     if ((read = getline(&line, &len, fp)) != -1) {
     61       char *pos;
     62       if ((pos = strchr(line, '\n')) != NULL) *pos = '\0';
     63       *contents = line;
     64     }
     65     free(line);
     66     fclose(fp);
     67     return 0;
     68   } else {
     69     ALOGE("fopen failed in readFile %s, errno=%d", filename.c_str(), errno);
     70   }
     71 
     72   return -1;
     73 }
     74 
     75 static int32_t writeFile(const std::string &filename,
     76                          const std::string &contents) {
     77   FILE *fp;
     78   int ret;
     79 
     80   fp = fopen(filename.c_str(), "w");
     81   if (fp != NULL) {
     82     ret = fputs(contents.c_str(), fp);
     83     fclose(fp);
     84     if (ret == EOF) {
     85       ALOGE("fputs failed in writeFile %s", filename.c_str());
     86       return -1;
     87     }
     88     return 0;
     89   } else {
     90     ALOGE("fopen failed in writeFile %s, errno=%d", filename.c_str(), errno);
     91   }
     92 
     93   return -1;
     94 }
     95 
     96 std::string appendRoleNodeHelper(const std::string &portName,
     97                                  PortRoleType type) {
     98   std::string node("/sys/class/typec/" + portName);
     99 
    100   switch (type) {
    101     case PortRoleType::DATA_ROLE:
    102       return node + "/data_role";
    103     case PortRoleType::POWER_ROLE:
    104       return node + "/power_role";
    105     case PortRoleType::MODE:
    106       return node + "/port_type";
    107     default:
    108       return "";
    109   }
    110 }
    111 
    112 std::string convertRoletoString(PortRole role) {
    113   if (role.type == PortRoleType::POWER_ROLE) {
    114     if (role.role == static_cast<uint32_t>(PortPowerRole::SOURCE))
    115       return "source";
    116     else if (role.role == static_cast<uint32_t>(PortPowerRole::SINK))
    117       return "sink";
    118   } else if (role.type == PortRoleType::DATA_ROLE) {
    119     if (role.role == static_cast<uint32_t>(PortDataRole::HOST)) return "host";
    120     if (role.role == static_cast<uint32_t>(PortDataRole::DEVICE))
    121       return "device";
    122   } else if (role.type == PortRoleType::MODE) {
    123     if (role.role == static_cast<uint32_t>(PortMode_1_1::UFP)) return "sink";
    124     if (role.role == static_cast<uint32_t>(PortMode_1_1::DFP)) return "source";
    125   }
    126   return "none";
    127 }
    128 
    129 void extractRole(std::string *roleName) {
    130   std::size_t first, last;
    131 
    132   first = roleName->find("[");
    133   last = roleName->find("]");
    134 
    135   if (first != std::string::npos && last != std::string::npos) {
    136     *roleName = roleName->substr(first + 1, last - first - 1);
    137   }
    138 }
    139 
    140 void switchToDrp(const std::string &portName) {
    141   std::string filename =
    142       appendRoleNodeHelper(std::string(portName.c_str()), PortRoleType::MODE);
    143   FILE *fp;
    144 
    145   if (filename != "") {
    146     fp = fopen(filename.c_str(), "w");
    147     if (fp != NULL) {
    148       int ret = fputs("dual", fp);
    149       fclose(fp);
    150       if (ret == EOF)
    151         ALOGE("Fatal: Error while switching back to drp");
    152     } else {
    153       ALOGE("Fatal: Cannot open file to switch back to drp");
    154     }
    155   } else {
    156     ALOGE("Fatal: invalid node type");
    157   }
    158 }
    159 
    160 bool switchMode(const hidl_string &portName,
    161                              const PortRole &newRole, struct Usb *usb) {
    162   std::string filename =
    163        appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
    164   std::string written;
    165   FILE *fp;
    166   bool roleSwitch = false;
    167 
    168   if (filename == "") {
    169     ALOGE("Fatal: invalid node type");
    170     return false;
    171   }
    172 
    173   fp = fopen(filename.c_str(), "w");
    174   if (fp != NULL) {
    175     // Hold the lock here to prevent loosing connected signals
    176     // as once the file is written the partner added signal
    177     // can arrive anytime.
    178     pthread_mutex_lock(&usb->mPartnerLock);
    179     usb->mPartnerUp = false;
    180     int ret = fputs(convertRoletoString(newRole).c_str(), fp);
    181     fclose(fp);
    182 
    183     if (ret != EOF) {
    184       struct timespec   to;
    185       struct timespec   now;
    186 
    187 wait_again:
    188       clock_gettime(CLOCK_MONOTONIC, &now);
    189       to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
    190       to.tv_nsec = now.tv_nsec;
    191 
    192       int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
    193       // There are no uevent signals which implies role swap timed out.
    194       if (err == ETIMEDOUT) {
    195         ALOGI("uevents wait timedout");
    196       // Sanity check.
    197       } else if (!usb->mPartnerUp) {
    198         goto wait_again;
    199       // Role switch succeeded since usb->mPartnerUp is true.
    200       } else {
    201         roleSwitch = true;
    202       }
    203     } else {
    204       ALOGI("Role switch failed while wrting to file");
    205     }
    206     pthread_mutex_unlock(&usb->mPartnerLock);
    207   }
    208 
    209   if (!roleSwitch)
    210     switchToDrp(std::string(portName.c_str()));
    211 
    212   return roleSwitch;
    213 }
    214 
    215 Usb::Usb()
    216         : mLock(PTHREAD_MUTEX_INITIALIZER),
    217           mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
    218           mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
    219           mPartnerUp(false) {
    220     pthread_condattr_t attr;
    221     if (pthread_condattr_init(&attr)) {
    222         ALOGE("pthread_condattr_init failed: %s", strerror(errno));
    223         abort();
    224     }
    225     if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
    226         ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
    227         abort();
    228     }
    229     if (pthread_cond_init(&mPartnerCV, &attr))  {
    230         ALOGE("pthread_cond_init failed: %s", strerror(errno));
    231         abort();
    232     }
    233     if (pthread_condattr_destroy(&attr)) {
    234         ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
    235         abort();
    236     }
    237 }
    238 
    239 
    240 Return<void> Usb::switchRole(const hidl_string &portName,
    241                              const V1_0::PortRole &newRole) {
    242   std::string filename =
    243       appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
    244   std::string written;
    245   FILE *fp;
    246   bool roleSwitch = false;
    247 
    248   if (filename == "") {
    249     ALOGE("Fatal: invalid node type");
    250     return Void();
    251   }
    252 
    253   pthread_mutex_lock(&mRoleSwitchLock);
    254 
    255   ALOGI("filename write: %s role:%s", filename.c_str(),
    256         convertRoletoString(newRole).c_str());
    257 
    258   if (newRole.type == PortRoleType::MODE) {
    259       roleSwitch = switchMode(portName, newRole, this);
    260   } else {
    261     fp = fopen(filename.c_str(), "w");
    262     if (fp != NULL) {
    263       int ret = fputs(convertRoletoString(newRole).c_str(), fp);
    264       fclose(fp);
    265       if ((ret != EOF) && !readFile(filename, &written)) {
    266         extractRole(&written);
    267         ALOGI("written: %s", written.c_str());
    268         if (written == convertRoletoString(newRole)) {
    269           roleSwitch = true;
    270         } else {
    271           ALOGE("Role switch failed");
    272         }
    273       } else {
    274         ALOGE("failed to update the new role");
    275       }
    276     } else {
    277       ALOGE("fopen failed");
    278     }
    279   }
    280 
    281   pthread_mutex_lock(&mLock);
    282   if (mCallback_1_0 != NULL) {
    283     Return<void> ret =
    284         mCallback_1_0->notifyRoleSwitchStatus(portName, newRole,
    285         roleSwitch ? Status::SUCCESS : Status::ERROR);
    286     if (!ret.isOk())
    287       ALOGE("RoleSwitchStatus error %s", ret.description().c_str());
    288   } else {
    289     ALOGE("Not notifying the userspace. Callback is not set");
    290   }
    291   pthread_mutex_unlock(&mLock);
    292   pthread_mutex_unlock(&mRoleSwitchLock);
    293 
    294   return Void();
    295 }
    296 
    297 Status getAccessoryConnected(const std::string &portName, std::string *accessory) {
    298   std::string filename =
    299     "/sys/class/typec/" + portName + "-partner/accessory_mode";
    300 
    301   if (readFile(filename, accessory)) {
    302     ALOGE("getAccessoryConnected: Failed to open filesystem node: %s",
    303           filename.c_str());
    304     return Status::ERROR;
    305   }
    306 
    307   return Status::SUCCESS;
    308 }
    309 
    310 Status getCurrentRoleHelper(const std::string &portName, bool connected,
    311                             PortRoleType type, uint32_t *currentRole) {
    312   std::string filename;
    313   std::string roleName;
    314   std::string accessory;
    315 
    316   // Mode
    317 
    318   if (type == PortRoleType::POWER_ROLE) {
    319     filename = "/sys/class/typec/" + portName + "/power_role";
    320     *currentRole = static_cast<uint32_t>(PortPowerRole::NONE);
    321   } else if (type == PortRoleType::DATA_ROLE) {
    322     filename = "/sys/class/typec/" + portName + "/data_role";
    323     *currentRole = static_cast<uint32_t>(PortDataRole::NONE);
    324   } else if (type == PortRoleType::MODE) {
    325     filename = "/sys/class/typec/" + portName + "/data_role";
    326     *currentRole = static_cast<uint32_t>(PortMode_1_1::NONE);
    327   } else {
    328     return Status::ERROR;
    329   }
    330 
    331   if (!connected) return Status::SUCCESS;
    332 
    333   if (type == PortRoleType::MODE) {
    334     if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
    335       return Status::ERROR;
    336     }
    337     if (accessory == "analog_audio") {
    338       *currentRole = static_cast<uint32_t>(PortMode_1_1::AUDIO_ACCESSORY);
    339       return Status::SUCCESS;
    340     } else if (accessory == "debug") {
    341       *currentRole = static_cast<uint32_t>(PortMode_1_1::DEBUG_ACCESSORY);
    342       return Status::SUCCESS;
    343     }
    344   }
    345 
    346   if (readFile(filename, &roleName)) {
    347     ALOGE("getCurrentRole: Failed to open filesystem node: %s",
    348           filename.c_str());
    349     return Status::ERROR;
    350   }
    351 
    352   extractRole(&roleName);
    353 
    354   if (roleName == "source") {
    355     *currentRole = static_cast<uint32_t>(PortPowerRole::SOURCE);
    356   } else if (roleName == "sink") {
    357     *currentRole = static_cast<uint32_t>(PortPowerRole::SINK);
    358   } else if (roleName == "host") {
    359     if (type == PortRoleType::DATA_ROLE)
    360       *currentRole = static_cast<uint32_t>(PortDataRole::HOST);
    361     else
    362       *currentRole = static_cast<uint32_t>(PortMode_1_1::DFP);
    363   } else if (roleName == "device") {
    364     if (type == PortRoleType::DATA_ROLE)
    365       *currentRole = static_cast<uint32_t>(PortDataRole::DEVICE);
    366     else
    367       *currentRole = static_cast<uint32_t>(PortMode_1_1::UFP);
    368   } else if (roleName != "none") {
    369     /* case for none has already been addressed.
    370      * so we check if the role isnt none.
    371      */
    372     return Status::UNRECOGNIZED_ROLE;
    373   }
    374 
    375   return Status::SUCCESS;
    376 }
    377 
    378 Status getTypeCPortNamesHelper(std::unordered_map<std::string, bool> *names) {
    379   DIR *dp;
    380 
    381   dp = opendir("/sys/class/typec");
    382   if (dp != NULL) {
    383     struct dirent *ep;
    384 
    385     while ((ep = readdir(dp))) {
    386       if (ep->d_type == DT_LNK) {
    387         if (std::string::npos == std::string(ep->d_name).find("-partner")) {
    388           std::unordered_map<std::string, bool>::const_iterator portName =
    389               names->find(ep->d_name);
    390           if (portName == names->end()) {
    391             names->insert({ep->d_name, false});
    392           }
    393         } else {
    394           (*names)[std::strtok(ep->d_name, "-")] = true;
    395         }
    396       }
    397     }
    398     closedir(dp);
    399     return Status::SUCCESS;
    400   }
    401 
    402   ALOGE("Failed to open /sys/class/typec");
    403   return Status::ERROR;
    404 }
    405 
    406 bool canSwitchRoleHelper(const std::string &portName, PortRoleType /*type*/) {
    407   std::string filename =
    408       "/sys/class/typec/" + portName + "-partner/supports_usb_power_delivery";
    409   std::string supportsPD;
    410 
    411   if (!readFile(filename, &supportsPD)) {
    412     if (supportsPD == "yes") {
    413       return true;
    414     }
    415   }
    416 
    417   return false;
    418 }
    419 
    420 /*
    421  * Reuse the same method for both V1_0 and V1_1 callback objects.
    422  * The caller of this method would reconstruct the V1_0::PortStatus
    423  * object if required.
    424  */
    425 Status getPortStatusHelper(hidl_vec<PortStatus_1_1> *currentPortStatus_1_1,
    426     bool V1_0) {
    427   std::unordered_map<std::string, bool> names;
    428   Status result = getTypeCPortNamesHelper(&names);
    429   int i = -1;
    430 
    431   if (result == Status::SUCCESS) {
    432     currentPortStatus_1_1->resize(names.size());
    433     for (std::pair<std::string, bool> port : names) {
    434       i++;
    435       ALOGI("%s", port.first.c_str());
    436       (*currentPortStatus_1_1)[i].status.portName = port.first;
    437 
    438       uint32_t currentRole;
    439       if (getCurrentRoleHelper(port.first, port.second,
    440                                PortRoleType::POWER_ROLE,
    441                                &currentRole) == Status::SUCCESS) {
    442         (*currentPortStatus_1_1)[i].status.currentPowerRole =
    443             static_cast<PortPowerRole>(currentRole);
    444       } else {
    445         ALOGE("Error while retreiving portNames");
    446         goto done;
    447       }
    448 
    449       if (getCurrentRoleHelper(port.first, port.second, PortRoleType::DATA_ROLE,
    450                                &currentRole) == Status::SUCCESS) {
    451         (*currentPortStatus_1_1)[i].status.currentDataRole =
    452             static_cast<PortDataRole>(currentRole);
    453       } else {
    454         ALOGE("Error while retreiving current port role");
    455         goto done;
    456       }
    457 
    458       if (getCurrentRoleHelper(port.first, port.second, PortRoleType::MODE,
    459                                &currentRole) == Status::SUCCESS) {
    460         (*currentPortStatus_1_1)[i].currentMode =
    461             static_cast<PortMode_1_1>(currentRole);
    462         (*currentPortStatus_1_1)[i].status.currentMode =
    463             static_cast<V1_0::PortMode>(currentRole);
    464       } else {
    465         ALOGE("Error while retreiving current data role");
    466         goto done;
    467       }
    468 
    469       (*currentPortStatus_1_1)[i].status.canChangeMode = true;
    470       (*currentPortStatus_1_1)[i].status.canChangeDataRole =
    471           port.second ? canSwitchRoleHelper(port.first, PortRoleType::DATA_ROLE)
    472                       : false;
    473       (*currentPortStatus_1_1)[i].status.canChangePowerRole =
    474           port.second
    475               ? canSwitchRoleHelper(port.first, PortRoleType::POWER_ROLE)
    476               : false;
    477 
    478       ALOGI("connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d",
    479             port.second, (*currentPortStatus_1_1)[i].status.canChangeMode,
    480             (*currentPortStatus_1_1)[i].status.canChangeDataRole,
    481             (*currentPortStatus_1_1)[i].status.canChangePowerRole);
    482 
    483       if (V1_0) {
    484         (*currentPortStatus_1_1)[i].status.supportedModes = V1_0::PortMode::DFP;
    485       } else {
    486         (*currentPortStatus_1_1)[i].supportedModes = PortMode_1_1::UFP | PortMode_1_1::DFP;
    487         (*currentPortStatus_1_1)[i].status.supportedModes = V1_0::PortMode::NONE;
    488         (*currentPortStatus_1_1)[i].status.currentMode = V1_0::PortMode::NONE;
    489       }
    490     }
    491     return Status::SUCCESS;
    492   }
    493 done:
    494   return Status::ERROR;
    495 }
    496 
    497 Return<void> Usb::queryPortStatus() {
    498   hidl_vec<PortStatus_1_1> currentPortStatus_1_1;
    499   hidl_vec<V1_0::PortStatus> currentPortStatus;
    500   Status status;
    501   sp<IUsbCallback> callback_V1_1 = IUsbCallback::castFrom(mCallback_1_0);
    502 
    503   pthread_mutex_lock(&mLock);
    504   if (mCallback_1_0 != NULL) {
    505     if (callback_V1_1 != NULL) {
    506       status = getPortStatusHelper(&currentPortStatus_1_1, false);
    507     } else {
    508       status = getPortStatusHelper(&currentPortStatus_1_1, true);
    509       currentPortStatus.resize(currentPortStatus_1_1.size());
    510       for (unsigned long i = 0; i < currentPortStatus_1_1.size(); i++)
    511         currentPortStatus[i] = currentPortStatus_1_1[i].status;
    512     }
    513 
    514     Return<void> ret;
    515 
    516     if (callback_V1_1 != NULL)
    517       ret = callback_V1_1->notifyPortStatusChange_1_1(currentPortStatus_1_1, status);
    518     else
    519       ret = mCallback_1_0->notifyPortStatusChange(currentPortStatus, status);
    520 
    521     if (!ret.isOk())
    522       ALOGE("queryPortStatus_1_1 error %s", ret.description().c_str());
    523   } else {
    524     ALOGI("Notifying userspace skipped. Callback is NULL");
    525   }
    526   pthread_mutex_unlock(&mLock);
    527 
    528   return Void();
    529 }
    530 
    531 struct data {
    532   int uevent_fd;
    533   android::hardware::usb::V1_1::implementation::Usb *usb;
    534 };
    535 
    536 static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
    537   char msg[UEVENT_MSG_LEN + 2];
    538   char *cp;
    539   int n;
    540 
    541   n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
    542   if (n <= 0) return;
    543   if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
    544     return;
    545 
    546   msg[n] = '\0';
    547   msg[n + 1] = '\0';
    548   cp = msg;
    549 
    550   while (*cp) {
    551     std::cmatch match;
    552     if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
    553        ALOGI("partner added");
    554        pthread_mutex_lock(&payload->usb->mPartnerLock);
    555        payload->usb->mPartnerUp = true;
    556        pthread_cond_signal(&payload->usb->mPartnerCV);
    557        pthread_mutex_unlock(&payload->usb->mPartnerLock);
    558     } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_"))) {
    559       hidl_vec<PortStatus_1_1> currentPortStatus_1_1;
    560       ALOGI("uevent received %s", cp);
    561       pthread_mutex_lock(&payload->usb->mLock);
    562       if (payload->usb->mCallback_1_0 != NULL) {
    563         sp<IUsbCallback> callback_V1_1 = IUsbCallback::castFrom(payload->usb->mCallback_1_0);
    564         Return<void> ret;
    565 
    566         // V1_1 callback
    567         if (callback_V1_1 != NULL) {
    568           Status status = getPortStatusHelper(&currentPortStatus_1_1, false);
    569           ret = callback_V1_1->notifyPortStatusChange_1_1(
    570               currentPortStatus_1_1, status);
    571         } else { // V1_0 callback
    572           Status status = getPortStatusHelper(&currentPortStatus_1_1, true);
    573 
    574           /*
    575            * Copying the result from getPortStatusHelper
    576            * into V1_0::PortStatus to pass back through
    577            * the V1_0 callback object.
    578            */
    579           hidl_vec<V1_0::PortStatus> currentPortStatus;
    580           currentPortStatus.resize(currentPortStatus_1_1.size());
    581           for (unsigned long i = 0; i < currentPortStatus_1_1.size(); i++)
    582             currentPortStatus[i] = currentPortStatus_1_1[i].status;
    583 
    584           ret = payload->usb->mCallback_1_0->notifyPortStatusChange(
    585               currentPortStatus, status);
    586         }
    587         if (!ret.isOk()) ALOGE("error %s", ret.description().c_str());
    588       } else {
    589         ALOGI("Notifying userspace skipped. Callback is NULL");
    590       }
    591       pthread_mutex_unlock(&payload->usb->mLock);
    592 
    593       //Role switch is not in progress and port is in disconnected state
    594       if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
    595         for (unsigned long i = 0; i < currentPortStatus_1_1.size(); i++) {
    596           DIR *dp = opendir(std::string("/sys/class/typec/"
    597               + std::string(currentPortStatus_1_1[i].status.portName.c_str())
    598               + "-partner").c_str());
    599           if (dp == NULL) {
    600               //PortRole role = {.role = static_cast<uint32_t>(PortMode::UFP)};
    601               switchToDrp(currentPortStatus_1_1[i].status.portName);
    602           } else {
    603               closedir(dp);
    604           }
    605         }
    606         pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
    607       }
    608       break;
    609     } else if (std::regex_match(cp, match,
    610           std::regex("add@(/devices/soc/a800000\\.ssusb/a800000\\.dwc3/xhci-hcd\\.0\\.auto/"
    611                      "usb\\d/\\d-\\d)/.*"))) {
    612       if (match.size() == 2) {
    613         std::csub_match submatch = match[1];
    614         checkUsbDeviceAutoSuspend("/sys" +  submatch.str());
    615       }
    616     }
    617 
    618     /* advance to after the next \0 */
    619     while (*cp++) {}
    620   }
    621 }
    622 
    623 void *work(void *param) {
    624   int epoll_fd, uevent_fd;
    625   struct epoll_event ev;
    626   int nevents = 0;
    627   struct data payload;
    628 
    629   ALOGE("creating thread");
    630 
    631   uevent_fd = uevent_open_socket(64 * 1024, true);
    632 
    633   if (uevent_fd < 0) {
    634     ALOGE("uevent_init: uevent_open_socket failed\n");
    635     return NULL;
    636   }
    637 
    638   payload.uevent_fd = uevent_fd;
    639   payload.usb = (android::hardware::usb::V1_1::implementation::Usb *)param;
    640 
    641   fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
    642 
    643   ev.events = EPOLLIN;
    644   ev.data.ptr = (void *)uevent_event;
    645 
    646   epoll_fd = epoll_create(64);
    647   if (epoll_fd == -1) {
    648     ALOGE("epoll_create failed; errno=%d", errno);
    649     goto error;
    650   }
    651 
    652   if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
    653     ALOGE("epoll_ctl failed; errno=%d", errno);
    654     goto error;
    655   }
    656 
    657   while (!destroyThread) {
    658     struct epoll_event events[64];
    659 
    660     nevents = epoll_wait(epoll_fd, events, 64, -1);
    661     if (nevents == -1) {
    662       if (errno == EINTR) continue;
    663       ALOGE("usb epoll_wait failed; errno=%d", errno);
    664       break;
    665     }
    666 
    667     for (int n = 0; n < nevents; ++n) {
    668       if (events[n].data.ptr)
    669         (*(void (*)(int, struct data *payload))events[n].data.ptr)(
    670             events[n].events, &payload);
    671     }
    672   }
    673 
    674   ALOGI("exiting worker thread");
    675 error:
    676   close(uevent_fd);
    677 
    678   if (epoll_fd >= 0) close(epoll_fd);
    679 
    680   return NULL;
    681 }
    682 
    683 void sighandler(int sig) {
    684   if (sig == SIGUSR1) {
    685     destroyThread = true;
    686     ALOGI("destroy set");
    687     return;
    688   }
    689   signal(SIGUSR1, sighandler);
    690 }
    691 
    692 Return<void> Usb::setCallback(const sp<V1_0::IUsbCallback> &callback) {
    693 
    694   sp<IUsbCallback> callback_V1_1 = IUsbCallback::castFrom(callback);
    695 
    696   if (callback != NULL)
    697       if (callback_V1_1 == NULL)
    698           ALOGI("Registering 1.0 callback");
    699 
    700   pthread_mutex_lock(&mLock);
    701   /*
    702    * When both the old callback and new callback values are NULL,
    703    * there is no need to spin off the worker thread.
    704    * When both the values are not NULL, we would already have a
    705    * worker thread running, so updating the callback object would
    706    * be suffice.
    707    */
    708   if ((mCallback_1_0 == NULL && callback == NULL) ||
    709       (mCallback_1_0 != NULL && callback != NULL)) {
    710     /*
    711      * Always store as V1_0 callback object. Type cast to V1_1
    712      * when the callback is actually invoked.
    713      */
    714     mCallback_1_0 = callback;
    715     pthread_mutex_unlock(&mLock);
    716     return Void();
    717   }
    718 
    719   mCallback_1_0 = callback;
    720   ALOGI("registering callback");
    721 
    722   // Kill the worker thread if the new callback is NULL.
    723   if (mCallback_1_0 == NULL) {
    724     pthread_mutex_unlock(&mLock);
    725     if (!pthread_kill(mPoll, SIGUSR1)) {
    726       pthread_join(mPoll, NULL);
    727       ALOGI("pthread destroyed");
    728     }
    729     return Void();
    730   }
    731 
    732   destroyThread = false;
    733   signal(SIGUSR1, sighandler);
    734 
    735   /*
    736    * Create a background thread if the old callback value is NULL
    737    * and being updated with a new value.
    738    */
    739   if (pthread_create(&mPoll, NULL, work, this)) {
    740     ALOGE("pthread creation failed %d", errno);
    741     mCallback_1_0 = NULL;
    742   }
    743 
    744   pthread_mutex_unlock(&mLock);
    745   return Void();
    746 }
    747 
    748 /*
    749  * whitelisting USB device idProduct and idVendor to allow auto suspend.
    750  */
    751 static bool canProductAutoSuspend(const std::string &deviceIdVendor,
    752     const std::string &deviceIdProduct) {
    753   if (deviceIdVendor == GOOGLE_USB_VENDOR_ID_STR &&
    754       deviceIdProduct == GOOGLE_USBC_35_ADAPTER_UNPLUGGED_ID_STR) {
    755     return true;
    756   }
    757   return false;
    758 }
    759 
    760 static bool canUsbDeviceAutoSuspend(const std::string &devicePath) {
    761   std::string deviceIdVendor;
    762   std::string deviceIdProduct;
    763   readFile(devicePath + "/idVendor", &deviceIdVendor);
    764   readFile(devicePath + "/idProduct", &deviceIdProduct);
    765 
    766   // deviceIdVendor and deviceIdProduct will be empty strings if readFile fails
    767   return canProductAutoSuspend(deviceIdVendor, deviceIdProduct);
    768 }
    769 
    770 /*
    771  * function to consume USB device plugin events (on receiving a
    772  * USB device path string), and enable autosupend on the USB device if
    773  * necessary.
    774  */
    775 void checkUsbDeviceAutoSuspend(const std::string& devicePath) {
    776   /*
    777    * Currently we only actively enable devices that should be autosuspended, and leave others
    778    * to the defualt.
    779    */
    780   if (canUsbDeviceAutoSuspend(devicePath)) {
    781     ALOGI("auto suspend usb device %s", devicePath.c_str());
    782     writeFile(devicePath + "/power/control", "auto");
    783   }
    784 }
    785 
    786 }  // namespace implementation
    787 }  // namespace V1_0
    788 }  // namespace usb
    789 }  // namespace hardware
    790 }  // namespace android
    791