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