• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.aidl-service"
18 
19 #include <android-base/logging.h>
20 #include <android-base/parseint.h>
21 #include <android-base/properties.h>
22 #include <android-base/strings.h>
23 #include <assert.h>
24 #include <cstring>
25 #include <dirent.h>
26 #include <pthread.h>
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <regex>
31 #include <thread>
32 #include <unordered_map>
33 
34 #include <cutils/uevent.h>
35 #include <sys/epoll.h>
36 #include <sys/eventfd.h>
37 #include <sys/timerfd.h>
38 #include <utils/Errors.h>
39 #include <utils/StrongPointer.h>
40 
41 #include "Usb.h"
42 
43 #include <aidl/android/frameworks/stats/IStats.h>
44 #include <android_hardware_usb_flags.h>
45 #include <pixelusb/UsbGadgetAidlCommon.h>
46 #include <pixelstats/StatsHelper.h>
47 
48 namespace usb_flags = android::hardware::usb::flags;
49 
50 using aidl::android::frameworks::stats::IStats;
51 using android::base::GetProperty;
52 using android::base::Join;
53 using android::base::ParseUint;
54 using android::base::Tokenize;
55 using android::base::Trim;
56 using android::hardware::google::pixel::getStatsService;
57 using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat;
58 using android::hardware::google::pixel::reportUsbPortOverheat;
59 
60 namespace aidl {
61 namespace android {
62 namespace hardware {
63 namespace usb {
64 // Set by the signal handler to destroy the thread
65 volatile bool destroyThread;
66 volatile bool destroyDisplayPortThread;
67 
68 string enabledPath;
69 constexpr char kHsi2cPath[] = "/sys/devices/platform/10cb0000.hsi2c";
70 constexpr char kI2CPath[] = "/sys/devices/platform/10cb0000.hsi2c/i2c-";
71 constexpr char kContaminantDetectionPath[] = "-0025/contaminant_detection";
72 constexpr char kDisplayPortDrmPath[] = "/sys/devices/platform/110f0000.drmdp/drm-displayport/";
73 constexpr char kDisplayPortUsbPath[] = "/sys/class/typec/port0-partner/";
74 constexpr char kComplianceWarningsPath[] = "device/non_compliant_reasons";
75 constexpr char kComplianceWarningBC12[] = "bc12";
76 constexpr char kComplianceWarningDebugAccessory[] = "debug-accessory";
77 constexpr char kComplianceWarningMissingRp[] = "missing_rp";
78 constexpr char kComplianceWarningOther[] = "other";
79 constexpr char kComplianceWarningInputPowerLimited[] = "input_power_limited";
80 constexpr char kStatusPath[] = "-0025/contaminant_detection_status";
81 constexpr char kSinkLimitEnable[] = "-0025/usb_limit_sink_enable";
82 constexpr char kSourceLimitEnable[] = "-0025/usb_limit_source_enable";
83 constexpr char kSinkLimitCurrent[] = "-0025/usb_limit_sink_current";
84 constexpr char kTypecPath[] = "/sys/class/typec";
85 constexpr char kDisableContatminantDetection[] = "vendor.usb.contaminantdisable";
86 constexpr char kOverheatStatsPath[] = "/sys/devices/platform/google,usbc_port_cooling_dev/";
87 constexpr char kOverheatStatsDev[] = "DRIVER=google,usbc_port_cooling_dev";
88 constexpr char kThermalZoneForTrip[] = "VIRTUAL-USB-THROTTLING";
89 constexpr char kThermalZoneForTempReadPrimary[] = "usb_pwr_therm2";
90 constexpr char kThermalZoneForTempReadSecondary1[] = "usb_pwr_therm";
91 constexpr char kThermalZoneForTempReadSecondary2[] = "qi_therm";
92 constexpr char kPogoUsbActive[] = "/sys/devices/platform/google,pogo/pogo_usb_active";
93 constexpr char kPogoEnableUsb[] = "/sys/devices/platform/google,pogo/enable_usb";
94 constexpr char kPowerSupplyUsbType[] = "/sys/class/power_supply/usb/usb_type";
95 constexpr char kIrqHpdCounPath[] = "-0025/irq_hpd_count";
96 constexpr char kUdcUeventRegex[] =
97     "/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3";
98 constexpr char kUdcStatePath[] =
99     "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state";
100 constexpr char kHost1UeventRegex[] =
101     "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb1/1-0:1.0";
102 constexpr char kHost1StatePath[] = "/sys/bus/usb/devices/usb1/1-0:1.0/usb1-port1/state";
103 constexpr char kHost2UeventRegex[] =
104     "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb2/2-0:1.0";
105 constexpr char kHost2StatePath[] = "/sys/bus/usb/devices/usb2/2-0:1.0/usb2-port1/state";
106 constexpr char kDataRolePath[] = "/sys/devices/platform/11210000.usb/new_data_role";
107 constexpr int kSamplingIntervalSec = 5;
108 void queryVersionHelper(android::hardware::usb::Usb *usb,
109                         std::vector<PortStatus> *currentPortStatus);
110 AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_assignment,
111                                                          string link_status, string vdo);
112 
enableUsbData(const string & in_portName,bool in_enable,int64_t in_transactionId)113 ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable,
114         int64_t in_transactionId) {
115     bool result = true;
116     std::vector<PortStatus> currentPortStatus;
117     string displayPortPartnerPath;
118 
119     ALOGI("Userspace turn %s USB data signaling. opID:%ld", in_enable ? "on" : "off",
120             in_transactionId);
121 
122     if (in_enable) {
123         if (!mUsbDataEnabled) {
124             if (!WriteStringToFile("1", USB_DATA_PATH)) {
125                 ALOGE("Not able to turn on usb connection notification");
126                 result = false;
127             }
128 
129             if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
130                 ALOGE("Gadget cannot be pulled up");
131                 result = false;
132             }
133 
134             if (!WriteStringToFile("1", DISPLAYPORT_ACTIVE_PATH)) {
135                 ALOGE("Failed to enable DisplayPort Alt Mode on port");
136             } else {
137                 ALOGI("Successfully enabled DisplayPort Alt Mode on port");
138             }
139 
140             if (getDisplayPortUsbPathHelper(&displayPortPartnerPath) == Status::SUCCESS) {
141                 size_t pos = displayPortPartnerPath.find("/displayport");
142                 if (pos != string::npos) {
143                     displayPortPartnerPath = displayPortPartnerPath.substr(0, pos) + "/mode1/active";
144                 }
145                 if (!WriteStringToFile("1", displayPortPartnerPath)) {
146                     ALOGE("Failed to enable DisplayPort Alt Mode on partner at %s",
147                             displayPortPartnerPath.c_str());
148                 } else {
149                     ALOGI("Successfully enabled DisplayPort Alt Mode on partner at %s",
150                             displayPortPartnerPath.c_str());
151                     setupDisplayPortPoll();
152                 }
153             }
154         }
155     } else {
156         if (!WriteStringToFile("1", ID_PATH)) {
157             ALOGE("Not able to turn off host mode");
158             result = false;
159         }
160 
161         if (!WriteStringToFile("0", VBUS_PATH)) {
162             ALOGE("Not able to set Vbus state");
163             result = false;
164         }
165 
166         if (!WriteStringToFile("0", USB_DATA_PATH)) {
167             ALOGE("Not able to turn off usb connection notification");
168             result = false;
169         }
170 
171         if (!WriteStringToFile("none", PULLUP_PATH)) {
172             ALOGE("Gadget cannot be pulled down");
173             result = false;
174         }
175 
176         if (getDisplayPortUsbPathHelper(&displayPortPartnerPath) == Status::SUCCESS) {
177             size_t pos = displayPortPartnerPath.find("/displayport");
178             if (pos != string::npos) {
179                 displayPortPartnerPath = displayPortPartnerPath.substr(0, pos) + "/mode1/active";
180             }
181             if (!WriteStringToFile("0", displayPortPartnerPath)) {
182                 ALOGE("Failed to disable DisplayPort Alt Mode on partner at %s",
183                         displayPortPartnerPath.c_str());
184             } else {
185                 ALOGI("Successfully disabled DisplayPort Alt Mode on partner at %s",
186                         displayPortPartnerPath.c_str());
187                 shutdownDisplayPortPoll(true);
188             }
189         }
190 
191         if (!WriteStringToFile("0", DISPLAYPORT_ACTIVE_PATH)) {
192             ALOGE("Failed to disable DisplayPort Alt Mode on port");
193         } else {
194             ALOGI("Successfully disabled DisplayPort Alt Mode on port");
195         }
196     }
197 
198     if (result) {
199         mUsbDataEnabled = in_enable;
200     }
201     pthread_mutex_lock(&mLock);
202     if (mCallback != NULL) {
203         ScopedAStatus ret = mCallback->notifyEnableUsbDataStatus(
204             in_portName, in_enable, result ? Status::SUCCESS : Status::ERROR, in_transactionId);
205         if (!ret.isOk())
206             ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
207     } else {
208         ALOGE("Not notifying the userspace. Callback is not set");
209     }
210     pthread_mutex_unlock(&mLock);
211     queryVersionHelper(this, &currentPortStatus);
212 
213     return ScopedAStatus::ok();
214 }
215 
enableUsbDataWhileDocked(const string & in_portName,int64_t in_transactionId)216 ScopedAStatus Usb::enableUsbDataWhileDocked(const string& in_portName,
217         int64_t in_transactionId) {
218     bool success = true;
219     bool notSupported = true;
220     std::vector<PortStatus> currentPortStatus;
221 
222     ALOGI("Userspace enableUsbDataWhileDocked  opID:%ld", in_transactionId);
223 
224     int flags = O_RDONLY;
225     ::android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(kPogoEnableUsb, flags)));
226     if (fd != -1) {
227         notSupported = false;
228         success = WriteStringToFile("1", kPogoEnableUsb);
229         if (!success) {
230             ALOGE("Write to enable_usb failed");
231         }
232     }
233 
234     pthread_mutex_lock(&mLock);
235     if (mCallback != NULL) {
236         ScopedAStatus ret = mCallback->notifyEnableUsbDataWhileDockedStatus(
237                 in_portName, notSupported ? Status::NOT_SUPPORTED :
238                 success ? Status::SUCCESS : Status::ERROR, in_transactionId);
239         if (!ret.isOk())
240             ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
241     } else {
242         ALOGE("Not notifying the userspace. Callback is not set");
243     }
244     pthread_mutex_unlock(&mLock);
245     queryVersionHelper(this, &currentPortStatus);
246 
247     return ScopedAStatus::ok();
248 }
249 
resetUsbPort(const std::string & in_portName,int64_t in_transactionId)250 ScopedAStatus Usb::resetUsbPort(const std::string& in_portName, int64_t in_transactionId) {
251     bool result = true;
252     std::vector<PortStatus> currentPortStatus;
253 
254     ALOGI("Userspace reset USB Port. opID:%ld", in_transactionId);
255 
256     if (!WriteStringToFile("none", PULLUP_PATH)) {
257         ALOGI("Gadget cannot be pulled down");
258         result = false;
259     }
260 
261     pthread_mutex_lock(&mLock);
262     if (mCallback != NULL) {
263         ::ndk::ScopedAStatus ret = mCallback->notifyResetUsbPortStatus(
264             in_portName, result ? Status::SUCCESS : Status::ERROR, in_transactionId);
265         if (!ret.isOk())
266             ALOGE("notifyTransactionStatus error %s", ret.getDescription().c_str());
267     } else {
268         ALOGE("Not notifying the userspace. Callback is not set");
269     }
270     pthread_mutex_unlock(&mLock);
271 
272     return ::ndk::ScopedAStatus::ok();
273 }
274 
getI2cBusHelper(string * name)275 Status getI2cBusHelper(string *name) {
276     DIR *dp;
277 
278     dp = opendir(kHsi2cPath);
279     if (dp != NULL) {
280         struct dirent *ep;
281 
282         while ((ep = readdir(dp))) {
283             if (ep->d_type == DT_DIR) {
284                 if (string::npos != string(ep->d_name).find("i2c-")) {
285                     std::strtok(ep->d_name, "-");
286                     *name = std::strtok(NULL, "-");
287                 }
288             }
289         }
290         closedir(dp);
291         return Status::SUCCESS;
292     }
293 
294     ALOGE("Failed to open %s", kHsi2cPath);
295     return Status::ERROR;
296 }
297 
queryMoistureDetectionStatus(std::vector<PortStatus> * currentPortStatus)298 Status queryMoistureDetectionStatus(std::vector<PortStatus> *currentPortStatus) {
299     string enabled, status, path, DetectedPath;
300 
301     (*currentPortStatus)[0].supportedContaminantProtectionModes
302             .push_back(ContaminantProtectionMode::FORCE_DISABLE);
303     (*currentPortStatus)[0].contaminantProtectionStatus = ContaminantProtectionStatus::NONE;
304     (*currentPortStatus)[0].contaminantDetectionStatus = ContaminantDetectionStatus::DISABLED;
305     (*currentPortStatus)[0].supportsEnableContaminantPresenceDetection = true;
306     (*currentPortStatus)[0].supportsEnableContaminantPresenceProtection = false;
307 
308     getI2cBusHelper(&path);
309     enabledPath = kI2CPath + path + "/" + path + kContaminantDetectionPath;
310     if (!ReadFileToString(enabledPath, &enabled)) {
311         ALOGE("Failed to open moisture_detection_enabled");
312         return Status::ERROR;
313     }
314 
315     enabled = Trim(enabled);
316     if (enabled == "1") {
317         DetectedPath = kI2CPath + path + "/" + path + kStatusPath;
318         if (!ReadFileToString(DetectedPath, &status)) {
319             ALOGE("Failed to open moisture_detected");
320             return Status::ERROR;
321         }
322         status = Trim(status);
323         if (status == "1") {
324             (*currentPortStatus)[0].contaminantDetectionStatus =
325                 ContaminantDetectionStatus::DETECTED;
326             (*currentPortStatus)[0].contaminantProtectionStatus =
327                 ContaminantProtectionStatus::FORCE_DISABLE;
328         } else {
329             (*currentPortStatus)[0].contaminantDetectionStatus =
330                 ContaminantDetectionStatus::NOT_DETECTED;
331         }
332     }
333 
334     ALOGI("ContaminantDetectionStatus:%d ContaminantProtectionStatus:%d",
335             (*currentPortStatus)[0].contaminantDetectionStatus,
336             (*currentPortStatus)[0].contaminantProtectionStatus);
337 
338     return Status::SUCCESS;
339 }
340 
queryNonCompliantChargerStatus(std::vector<PortStatus> * currentPortStatus)341 Status queryNonCompliantChargerStatus(std::vector<PortStatus> *currentPortStatus) {
342     string reasons, path;
343 
344     for (int i = 0; i < currentPortStatus->size(); i++) {
345         (*currentPortStatus)[i].supportsComplianceWarnings = true;
346         path = string(kTypecPath) + "/" + (*currentPortStatus)[i].portName + "/" +
347                 string(kComplianceWarningsPath);
348         if (ReadFileToString(path.c_str(), &reasons)) {
349             std::vector<string> reasonsList = Tokenize(reasons.c_str(), "[], \n\0");
350             for (string reason : reasonsList) {
351                 if (!strncmp(reason.c_str(), kComplianceWarningDebugAccessory,
352                             strlen(kComplianceWarningDebugAccessory))) {
353                     (*currentPortStatus)[i].complianceWarnings.push_back(ComplianceWarning::DEBUG_ACCESSORY);
354                     continue;
355                 }
356                 if (!strncmp(reason.c_str(), kComplianceWarningBC12,
357                             strlen(kComplianceWarningBC12))) {
358                     (*currentPortStatus)[i].complianceWarnings.push_back(ComplianceWarning::BC_1_2);
359                     continue;
360                 }
361                 if (!strncmp(reason.c_str(), kComplianceWarningMissingRp,
362                             strlen(kComplianceWarningMissingRp))) {
363                     (*currentPortStatus)[i].complianceWarnings.push_back(ComplianceWarning::MISSING_RP);
364                     continue;
365                 }
366                 if (!strncmp(reason.c_str(), kComplianceWarningOther,
367                              strlen(kComplianceWarningOther)) ||
368                     !strncmp(reason.c_str(), kComplianceWarningInputPowerLimited,
369                              strlen(kComplianceWarningInputPowerLimited))) {
370                     if (usb_flags::enable_usb_data_compliance_warning() &&
371                         usb_flags::enable_input_power_limited_warning()) {
372                         ALOGI("Report through INPUT_POWER_LIMITED warning");
373                         (*currentPortStatus)[i].complianceWarnings.push_back(
374                             ComplianceWarning::INPUT_POWER_LIMITED);
375                         continue;
376                     } else {
377                         (*currentPortStatus)[i].complianceWarnings.push_back(
378                             ComplianceWarning::OTHER);
379                         continue;
380                     }
381                 }
382             }
383             if ((*currentPortStatus)[i].complianceWarnings.size() > 0 &&
384                  (*currentPortStatus)[i].currentPowerRole == PortPowerRole::NONE) {
385                 (*currentPortStatus)[i].currentMode = PortMode::UFP;
386                 (*currentPortStatus)[i].currentPowerRole = PortPowerRole::SINK;
387                 (*currentPortStatus)[i].currentDataRole = PortDataRole::NONE;
388                 (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::CONNECTED;
389             }
390         }
391     }
392     return Status::SUCCESS;
393 }
394 
appendRoleNodeHelper(const string & portName,PortRole::Tag tag)395 string appendRoleNodeHelper(const string &portName, PortRole::Tag tag) {
396     string node("/sys/class/typec/" + portName);
397 
398     switch (tag) {
399         case PortRole::dataRole:
400             return node + "/data_role";
401         case PortRole::powerRole:
402             return node + "/power_role";
403         case PortRole::mode:
404             return node + "/port_type";
405         default:
406             return "";
407     }
408 }
409 
convertRoletoString(PortRole role)410 string convertRoletoString(PortRole role) {
411     if (role.getTag() == PortRole::powerRole) {
412         if (role.get<PortRole::powerRole>() == PortPowerRole::SOURCE)
413             return "source";
414         else if (role.get<PortRole::powerRole>() == PortPowerRole::SINK)
415             return "sink";
416     } else if (role.getTag() == PortRole::dataRole) {
417         if (role.get<PortRole::dataRole>() == PortDataRole::HOST)
418             return "host";
419         if (role.get<PortRole::dataRole>() == PortDataRole::DEVICE)
420             return "device";
421     } else if (role.getTag() == PortRole::mode) {
422         if (role.get<PortRole::mode>() == PortMode::UFP)
423             return "sink";
424         if (role.get<PortRole::mode>() == PortMode::DFP)
425             return "source";
426     }
427     return "none";
428 }
429 
extractRole(string * roleName)430 void extractRole(string *roleName) {
431     std::size_t first, last;
432 
433     first = roleName->find("[");
434     last = roleName->find("]");
435 
436     if (first != string::npos && last != string::npos) {
437         *roleName = roleName->substr(first + 1, last - first - 1);
438     }
439 }
440 
switchToDrp(const string & portName)441 void switchToDrp(const string &portName) {
442     string filename = appendRoleNodeHelper(string(portName.c_str()), PortRole::mode);
443     FILE *fp;
444 
445     if (filename != "") {
446         fp = fopen(filename.c_str(), "w");
447         if (fp != NULL) {
448             int ret = fputs("dual", fp);
449             fclose(fp);
450             if (ret == EOF)
451                 ALOGE("Fatal: Error while switching back to drp");
452         } else {
453             ALOGE("Fatal: Cannot open file to switch back to drp");
454         }
455     } else {
456         ALOGE("Fatal: invalid node type");
457     }
458 }
459 
switchMode(const string & portName,const PortRole & in_role,struct Usb * usb)460 bool switchMode(const string &portName, const PortRole &in_role, struct Usb *usb) {
461     string filename = appendRoleNodeHelper(string(portName.c_str()), in_role.getTag());
462     string written;
463     FILE *fp;
464     bool roleSwitch = false;
465 
466     if (filename == "") {
467         ALOGE("Fatal: invalid node type");
468         return false;
469     }
470 
471     fp = fopen(filename.c_str(), "w");
472     if (fp != NULL) {
473         // Hold the lock here to prevent loosing connected signals
474         // as once the file is written the partner added signal
475         // can arrive anytime.
476         pthread_mutex_lock(&usb->mPartnerLock);
477         usb->mPartnerUp = false;
478         int ret = fputs(convertRoletoString(in_role).c_str(), fp);
479         fclose(fp);
480 
481         if (ret != EOF) {
482             struct timespec to;
483             struct timespec now;
484 
485         wait_again:
486             clock_gettime(CLOCK_MONOTONIC, &now);
487             to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
488             to.tv_nsec = now.tv_nsec;
489 
490             int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
491             // There are no uevent signals which implies role swap timed out.
492             if (err == ETIMEDOUT) {
493                 ALOGI("uevents wait timedout");
494                 // Validity check.
495             } else if (!usb->mPartnerUp) {
496                 goto wait_again;
497                 // Role switch succeeded since usb->mPartnerUp is true.
498             } else {
499                 roleSwitch = true;
500             }
501         } else {
502             ALOGI("Role switch failed while wrting to file");
503         }
504         pthread_mutex_unlock(&usb->mPartnerLock);
505     }
506 
507     if (!roleSwitch)
508         switchToDrp(string(portName.c_str()));
509 
510     return roleSwitch;
511 }
512 
updatePortStatus(android::hardware::usb::Usb * usb)513 void updatePortStatus(android::hardware::usb::Usb *usb) {
514     std::vector<PortStatus> currentPortStatus;
515 
516     queryVersionHelper(usb, &currentPortStatus);
517 }
518 
Usb()519 Usb::Usb()
520     : mLock(PTHREAD_MUTEX_INITIALIZER),
521       mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
522       mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
523       mPartnerUp(false),
524       mUsbDataSessionMonitor(kUdcUeventRegex, kUdcStatePath, kHost1UeventRegex, kHost1StatePath,
525                              kHost2UeventRegex, kHost2StatePath, kDataRolePath,
526                              std::bind(&updatePortStatus, this)),
527       mOverheat(ZoneInfo(TemperatureType::USB_PORT, kThermalZoneForTrip,
528                          ThrottlingSeverity::CRITICAL),
529                 {ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadPrimary,
530                           ThrottlingSeverity::NONE),
531                  ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary1,
532                           ThrottlingSeverity::NONE),
533                  ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary2,
534                           ThrottlingSeverity::NONE)}, kSamplingIntervalSec),
535       mUsbDataEnabled(true),
536       mDisplayPortPollRunning(false),
537       mDisplayPortPollStarting(false),
538       mDisplayPortCVLock(PTHREAD_MUTEX_INITIALIZER),
539       mDisplayPortLock(PTHREAD_MUTEX_INITIALIZER) {
540     pthread_condattr_t attr;
541     if (pthread_condattr_init(&attr)) {
542         ALOGE("pthread_condattr_init failed: %s", strerror(errno));
543         abort();
544     }
545     if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
546         ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
547         abort();
548     }
549     if (pthread_cond_init(&mPartnerCV, &attr)) {
550         ALOGE("pthread_cond_init failed: %s", strerror(errno));
551         abort();
552     }
553     if (pthread_cond_init(&mDisplayPortCV, &attr)) {
554         ALOGE("usbdp: pthread_cond_init failed: %s", strerror(errno));
555         abort();
556     }
557     if (pthread_condattr_destroy(&attr)) {
558         ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
559         abort();
560     }
561     mDisplayPortEventPipe = eventfd(0, EFD_NONBLOCK);
562     if (mDisplayPortEventPipe == -1) {
563         ALOGE("mDisplayPortEventPipe eventfd failed: %s", strerror(errno));
564         abort();
565     }
566     mDisplayPortDebounceTimer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
567     if (mDisplayPortDebounceTimer == -1) {
568         ALOGE("mDisplayPortDebounceTimer timerfd failed: %s", strerror(errno));
569         abort();
570     }
571     mDisplayPortActivateTimer = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
572     if (mDisplayPortActivateTimer == -1) {
573         ALOGE("mDisplayPortActivateTimer timerfd failed: %s", strerror(errno));
574         abort();
575     }
576 
577     ALOGI("feature flag enable_usb_data_compliance_warning: %d",
578           usb_flags::enable_usb_data_compliance_warning());
579     ALOGI("feature flag enable_input_power_limited_warning: %d",
580           usb_flags::enable_input_power_limited_warning());
581 }
582 
switchRole(const string & in_portName,const PortRole & in_role,int64_t in_transactionId)583 ScopedAStatus Usb::switchRole(const string& in_portName, const PortRole& in_role,
584         int64_t in_transactionId) {
585     string filename = appendRoleNodeHelper(string(in_portName.c_str()), in_role.getTag());
586     string written;
587     FILE *fp;
588     bool roleSwitch = false;
589 
590     if (filename == "") {
591         ALOGE("Fatal: invalid node type");
592         return ScopedAStatus::ok();
593     }
594 
595     pthread_mutex_lock(&mRoleSwitchLock);
596 
597     ALOGI("filename write: %s role:%s", filename.c_str(), convertRoletoString(in_role).c_str());
598 
599     if (in_role.getTag() == PortRole::mode) {
600         roleSwitch = switchMode(in_portName, in_role, this);
601     } else {
602         fp = fopen(filename.c_str(), "w");
603         if (fp != NULL) {
604             int ret = fputs(convertRoletoString(in_role).c_str(), fp);
605             if (ret == EAGAIN) {
606                 ALOGI("role switch busy, retry in %d ms", ROLE_SWAP_RETRY_MS);
607                 std::this_thread::sleep_for(std::chrono::milliseconds(ROLE_SWAP_RETRY_MS));
608                 ret = fputs(convertRoletoString(in_role).c_str(), fp);
609             }
610             fclose(fp);
611             if ((ret != EOF) && ReadFileToString(filename, &written)) {
612                 written = Trim(written);
613                 extractRole(&written);
614                 ALOGI("written: %s", written.c_str());
615                 if (written == convertRoletoString(in_role)) {
616                     roleSwitch = true;
617                 } else {
618                     ALOGE("Role switch failed");
619                 }
620             } else {
621                 ALOGE("failed to update the new role");
622             }
623         } else {
624             ALOGE("fopen failed");
625         }
626     }
627 
628     pthread_mutex_lock(&mLock);
629     if (mCallback != NULL) {
630          ScopedAStatus ret = mCallback->notifyRoleSwitchStatus(
631             in_portName, in_role, roleSwitch ? Status::SUCCESS : Status::ERROR, in_transactionId);
632         if (!ret.isOk())
633             ALOGE("RoleSwitchStatus error %s", ret.getDescription().c_str());
634     } else {
635         ALOGE("Not notifying the userspace. Callback is not set");
636     }
637     pthread_mutex_unlock(&mLock);
638     pthread_mutex_unlock(&mRoleSwitchLock);
639 
640     return ScopedAStatus::ok();
641 }
642 
limitPowerTransfer(const string & in_portName,bool in_limit,int64_t in_transactionId)643 ScopedAStatus Usb::limitPowerTransfer(const string& in_portName, bool in_limit,
644         int64_t in_transactionId) {
645     bool sessionFail = false, success;
646     std::vector<PortStatus> currentPortStatus;
647     string path, sinkLimitEnablePath, currentLimitPath, sourceLimitEnablePath;
648 
649     getI2cBusHelper(&path);
650     sinkLimitEnablePath = kI2CPath + path + "/" + path + kSinkLimitEnable;
651     currentLimitPath = kI2CPath + path + "/" + path + kSinkLimitCurrent;
652     sourceLimitEnablePath = kI2CPath + path + "/" + path + kSourceLimitEnable;
653 
654     pthread_mutex_lock(&mLock);
655     if (in_limit) {
656         success = WriteStringToFile("0", currentLimitPath);
657         if (!success) {
658             ALOGE("Failed to set sink current limit");
659             sessionFail = true;
660         }
661     }
662     success = WriteStringToFile(in_limit ? "1" : "0", sinkLimitEnablePath);
663     if (!success) {
664         ALOGE("Failed to %s sink current limit: %s", in_limit ? "enable" : "disable",
665               sinkLimitEnablePath.c_str());
666         sessionFail = true;
667     }
668     success = WriteStringToFile(in_limit ? "1" : "0", sourceLimitEnablePath);
669     if (!success) {
670         ALOGE("Failed to %s source current limit: %s", in_limit ? "enable" : "disable",
671               sourceLimitEnablePath.c_str());
672         sessionFail = true;
673     }
674 
675     ALOGI("limitPowerTransfer limit:%c opId:%ld", in_limit ? 'y' : 'n', in_transactionId);
676     if (mCallback != NULL && in_transactionId >= 0) {
677         ScopedAStatus ret = mCallback->notifyLimitPowerTransferStatus(
678                 in_portName, in_limit, sessionFail ? Status::ERROR : Status::SUCCESS,
679                 in_transactionId);
680         if (!ret.isOk())
681             ALOGE("limitPowerTransfer error %s", ret.getDescription().c_str());
682     } else {
683         ALOGE("Not notifying the userspace. Callback is not set");
684     }
685 
686     pthread_mutex_unlock(&mLock);
687     queryVersionHelper(this, &currentPortStatus);
688 
689     return ScopedAStatus::ok();
690 }
691 
queryPowerTransferStatus(std::vector<PortStatus> * currentPortStatus)692 Status queryPowerTransferStatus(std::vector<PortStatus> *currentPortStatus) {
693     string limitedPath, enabled, path;
694 
695     getI2cBusHelper(&path);
696     limitedPath = kI2CPath + path + "/" + path + kSinkLimitEnable;
697     if (!ReadFileToString(limitedPath, &enabled)) {
698         ALOGE("Failed to open limit_sink_enable");
699         return Status::ERROR;
700     }
701 
702     enabled = Trim(enabled);
703     (*currentPortStatus)[0].powerTransferLimited = enabled == "1";
704 
705     ALOGI("powerTransferLimited:%d", (*currentPortStatus)[0].powerTransferLimited ? 1 : 0);
706     return Status::SUCCESS;
707 }
708 
getAccessoryConnected(const string & portName,string * accessory)709 Status getAccessoryConnected(const string &portName, string *accessory) {
710     string filename = "/sys/class/typec/" + portName + "-partner/accessory_mode";
711 
712     if (!ReadFileToString(filename, accessory)) {
713         ALOGE("getAccessoryConnected: Failed to open filesystem node: %s", filename.c_str());
714         return Status::ERROR;
715     }
716     *accessory = Trim(*accessory);
717 
718     return Status::SUCCESS;
719 }
720 
getCurrentRoleHelper(const string & portName,bool connected,PortRole * currentRole)721 Status getCurrentRoleHelper(const string &portName, bool connected, PortRole *currentRole) {
722     string filename;
723     string roleName;
724     string accessory;
725 
726     // Mode
727 
728     if (currentRole->getTag() == PortRole::powerRole) {
729         filename = "/sys/class/typec/" + portName + "/power_role";
730         currentRole->set<PortRole::powerRole>(PortPowerRole::NONE);
731     } else if (currentRole->getTag() == PortRole::dataRole) {
732         filename = "/sys/class/typec/" + portName + "/data_role";
733         currentRole->set<PortRole::dataRole>(PortDataRole::NONE);
734     } else if (currentRole->getTag() == PortRole::mode) {
735         filename = "/sys/class/typec/" + portName + "/data_role";
736         currentRole->set<PortRole::mode>(PortMode::NONE);
737     } else {
738         return Status::ERROR;
739     }
740 
741     if (!connected)
742         return Status::SUCCESS;
743 
744     if (currentRole->getTag() == PortRole::mode) {
745         if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
746             return Status::ERROR;
747         }
748         if (accessory == "analog_audio") {
749             currentRole->set<PortRole::mode>(PortMode::AUDIO_ACCESSORY);
750             return Status::SUCCESS;
751         } else if (accessory == "debug") {
752             currentRole->set<PortRole::mode>(PortMode::DEBUG_ACCESSORY);
753             return Status::SUCCESS;
754         }
755     }
756 
757     if (!ReadFileToString(filename, &roleName)) {
758         ALOGE("getCurrentRole: Failed to open filesystem node: %s", filename.c_str());
759         return Status::ERROR;
760     }
761 
762     roleName = Trim(roleName);
763     extractRole(&roleName);
764 
765     if (roleName == "source") {
766         currentRole->set<PortRole::powerRole>(PortPowerRole::SOURCE);
767     } else if (roleName == "sink") {
768         currentRole->set<PortRole::powerRole>(PortPowerRole::SINK);
769     } else if (roleName == "host") {
770         if (currentRole->getTag() == PortRole::dataRole)
771             currentRole->set<PortRole::dataRole>(PortDataRole::HOST);
772         else
773             currentRole->set<PortRole::mode>(PortMode::DFP);
774     } else if (roleName == "device") {
775         if (currentRole->getTag() == PortRole::dataRole)
776             currentRole->set<PortRole::dataRole>(PortDataRole::DEVICE);
777         else
778             currentRole->set<PortRole::mode>(PortMode::UFP);
779     } else if (roleName != "none") {
780         /* case for none has already been addressed.
781          * so we check if the role isn't none.
782          */
783         return Status::UNRECOGNIZED_ROLE;
784     }
785     return Status::SUCCESS;
786 }
787 
getTypeCPortNamesHelper(std::unordered_map<string,bool> * names)788 Status getTypeCPortNamesHelper(std::unordered_map<string, bool> *names) {
789     DIR *dp;
790 
791     dp = opendir(kTypecPath);
792     if (dp != NULL) {
793         struct dirent *ep;
794 
795         while ((ep = readdir(dp))) {
796             if (ep->d_type == DT_LNK) {
797                 if (string::npos == string(ep->d_name).find("-partner")) {
798                     std::unordered_map<string, bool>::const_iterator portName =
799                         names->find(ep->d_name);
800                     if (portName == names->end()) {
801                         names->insert({ep->d_name, false});
802                     }
803                 } else {
804                     (*names)[std::strtok(ep->d_name, "-")] = true;
805                 }
806             }
807         }
808         closedir(dp);
809         return Status::SUCCESS;
810     }
811 
812     ALOGE("Failed to open /sys/class/typec");
813     return Status::ERROR;
814 }
815 
canSwitchRoleHelper(const string & portName)816 bool canSwitchRoleHelper(const string &portName) {
817     string filename = "/sys/class/typec/" + portName + "-partner/supports_usb_power_delivery";
818     string supportsPD;
819 
820     if (ReadFileToString(filename, &supportsPD)) {
821         supportsPD = Trim(supportsPD);
822         if (supportsPD == "yes") {
823             return true;
824         }
825     }
826 
827     return false;
828 }
829 
getPortStatusHelper(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)830 Status getPortStatusHelper(android::hardware::usb::Usb *usb,
831         std::vector<PortStatus> *currentPortStatus) {
832     std::unordered_map<string, bool> names;
833     Status result = getTypeCPortNamesHelper(&names);
834     int i = -1;
835 
836     if (result == Status::SUCCESS) {
837         currentPortStatus->resize(names.size());
838         for (std::pair<string, bool> port : names) {
839             i++;
840             ALOGI("%s", port.first.c_str());
841             (*currentPortStatus)[i].portName = port.first;
842 
843             PortRole currentRole;
844             currentRole.set<PortRole::powerRole>(PortPowerRole::NONE);
845             if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS){
846                 (*currentPortStatus)[i].currentPowerRole = currentRole.get<PortRole::powerRole>();
847             } else {
848                 ALOGE("Error while retrieving portNames");
849                 goto done;
850             }
851 
852             currentRole.set<PortRole::dataRole>(PortDataRole::NONE);
853             if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
854                 (*currentPortStatus)[i].currentDataRole = currentRole.get<PortRole::dataRole>();
855             } else {
856                 ALOGE("Error while retrieving current port role");
857                 goto done;
858             }
859 
860             currentRole.set<PortRole::mode>(PortMode::NONE);
861             if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
862                 (*currentPortStatus)[i].currentMode = currentRole.get<PortRole::mode>();
863             } else {
864                 ALOGE("Error while retrieving current data role");
865                 goto done;
866             }
867 
868             (*currentPortStatus)[i].canChangeMode = true;
869             (*currentPortStatus)[i].canChangeDataRole =
870                 port.second ? canSwitchRoleHelper(port.first) : false;
871             (*currentPortStatus)[i].canChangePowerRole =
872                 port.second ? canSwitchRoleHelper(port.first) : false;
873 
874             (*currentPortStatus)[i].supportedModes.push_back(PortMode::DRP);
875 
876             bool dataEnabled = true;
877             string pogoUsbActive = "0";
878             if (ReadFileToString(string(kPogoUsbActive), &pogoUsbActive) &&
879                 stoi(Trim(pogoUsbActive)) == 1) {
880                 (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::DISABLED_DOCK);
881                 dataEnabled = false;
882             }
883             if (!usb->mUsbDataEnabled) {
884                 (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::DISABLED_FORCE);
885                 dataEnabled = false;
886             }
887             if (dataEnabled) {
888                 (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::ENABLED);
889             }
890 
891             // When connected return powerBrickStatus
892             if (port.second) {
893                 string usbType;
894                 if (ReadFileToString(string(kPowerSupplyUsbType), &usbType)) {
895                     if (strstr(usbType.c_str(), "[D")) {
896                         (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::CONNECTED;
897                     } else if (strstr(usbType.c_str(), "[U")) {
898                         (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::UNKNOWN;
899                     } else {
900                         (*currentPortStatus)[i].powerBrickStatus =
901                                 PowerBrickStatus::NOT_CONNECTED;
902                     }
903                 } else {
904                     ALOGE("Error while reading usb_type");
905                 }
906             } else {
907                 (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::NOT_CONNECTED;
908             }
909 
910             ALOGI("%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
911                   "usbDataEnabled:%d",
912                 i, port.first.c_str(), port.second,
913                 (*currentPortStatus)[i].canChangeMode,
914                 (*currentPortStatus)[i].canChangeDataRole,
915                 (*currentPortStatus)[i].canChangePowerRole,
916                 dataEnabled ? 1 : 0);
917         }
918 
919         return Status::SUCCESS;
920     }
921 done:
922     return Status::ERROR;
923 }
924 
925 /* DisplayPort Helper Functions Start */
926 
parsePinAssignmentHelper(string pinAssignments)927 DisplayPortAltModePinAssignment parsePinAssignmentHelper(string pinAssignments) {
928     size_t pos = pinAssignments.find("[");
929     if (pos != string::npos) {
930         pinAssignments = pinAssignments.substr(pos+1, 1);
931         if (pinAssignments == "C") {
932             return DisplayPortAltModePinAssignment::C;
933         } else if (pinAssignments == "D") {
934             return DisplayPortAltModePinAssignment::D;
935         } else if (pinAssignments == "E") {
936             return DisplayPortAltModePinAssignment::E;
937         }
938     }
939     return DisplayPortAltModePinAssignment::NONE;
940 }
941 
parseLinkTrainingStatusHelper(string linkTrainingStatus)942 LinkTrainingStatus parseLinkTrainingStatusHelper(string linkTrainingStatus) {
943     linkTrainingStatus = Trim(linkTrainingStatus);
944     if (linkTrainingStatus == LINK_TRAINING_STATUS_SUCCESS) {
945         return LinkTrainingStatus::SUCCESS;
946     } else if (linkTrainingStatus == LINK_TRAINING_STATUS_FAILURE || \
947                linkTrainingStatus == LINK_TRAINING_STATUS_FAILURE_SINK) {
948         return LinkTrainingStatus::FAILURE;
949     }
950     return LinkTrainingStatus::UNKNOWN;
951 }
952 
isDisplayPortPlugHelper(string vdoString)953 bool isDisplayPortPlugHelper(string vdoString) {
954     unsigned long vdo;
955     unsigned long receptacleFlag = 1 << DISPLAYPORT_CAPABILITIES_RECEPTACLE_BIT;
956 
957     vdoString = Trim(vdoString);
958     if (ParseUint(vdoString.c_str(), &vdo)) {
959         /* We check to see if receptacleFlag is 0, meaning that the DP interface is presented on a
960          * USB-C plug.
961          */
962         return !(vdo & receptacleFlag);
963     } else {
964         ALOGE("usbdp: isDisplayPortPlugHelper: errno:%d", errno);
965     }
966 
967     return false;
968 }
969 
constructAltModeData(string hpd,string pin_assignment,string link_status,string vdo)970 AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_assignment,
971                                                          string link_status, string vdo) {
972     AltModeData::DisplayPortAltModeData dpData;
973 
974     // vdo
975     if (isDisplayPortPlugHelper(vdo)) {
976         dpData.cableStatus = DisplayPortAltModeStatus::CAPABLE;
977     } else {
978         dpData.partnerSinkStatus = DisplayPortAltModeStatus::CAPABLE;
979     }
980 
981     // hpd, status
982      if (!strncmp(hpd.c_str(), "1", strlen("1"))) {
983         dpData.hpd = true;
984     }
985 
986     // pin
987     dpData.pinAssignment = parsePinAssignmentHelper(pin_assignment);
988 
989     // link training
990     link_status = Trim(link_status);
991     dpData.linkTrainingStatus = parseLinkTrainingStatusHelper(link_status);
992     if (dpData.linkTrainingStatus == LinkTrainingStatus::SUCCESS) {
993         dpData.partnerSinkStatus = dpData.partnerSinkStatus == DisplayPortAltModeStatus::CAPABLE ? \
994                 DisplayPortAltModeStatus::ENABLED : DisplayPortAltModeStatus::UNKNOWN;
995         dpData.cableStatus = dpData.cableStatus == DisplayPortAltModeStatus::CAPABLE ? \
996                 DisplayPortAltModeStatus::ENABLED : DisplayPortAltModeStatus::UNKNOWN;
997         if (dpData.partnerSinkStatus == DisplayPortAltModeStatus::ENABLED) {
998             dpData.cableStatus = DisplayPortAltModeStatus::ENABLED;
999         }
1000     } else if (dpData.linkTrainingStatus == LinkTrainingStatus::FAILURE &&
1001                dpData.partnerSinkStatus == DisplayPortAltModeStatus::CAPABLE) {
1002         // 2.0 cable that fails EDID reports not capable, other link training failures assume
1003         // 3.0 cable that fails in all other cases.
1004         dpData.cableStatus = (link_status == LINK_TRAINING_STATUS_FAILURE_SINK) ? \
1005                 DisplayPortAltModeStatus::NOT_CAPABLE : DisplayPortAltModeStatus::CAPABLE;
1006     }
1007 
1008     return dpData;
1009 }
1010 
queryPartnerSvids(std::vector<string> * svids)1011 Status queryPartnerSvids(std::vector<string> *svids) {
1012     DIR *dp;
1013 
1014     dp = opendir(kDisplayPortUsbPath);
1015     if (dp != NULL) {
1016         struct dirent *ep;
1017         // Iterate through directories for Alt Mode SVIDs
1018         while ((ep = readdir(dp))) {
1019             if (ep->d_type == DT_DIR) {
1020                 string svid;
1021                 string portPartnerPath = string(kDisplayPortUsbPath) + string(ep->d_name) + "/svid";
1022                 if (ReadFileToString(portPartnerPath, &svid)) {
1023                     (*svids).push_back(Trim(svid));
1024                 }
1025             }
1026         }
1027         closedir(dp);
1028     } else {
1029         return Status::ERROR;
1030     }
1031     return Status::SUCCESS;
1032 }
1033 
1034 /* DisplayPort Helper Functions End */
1035 
1036 // Only care about first port which must support DisplayPortAltMode
queryDisplayPortStatus(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)1037 Status queryDisplayPortStatus(android::hardware::usb::Usb *usb,
1038                               std::vector<PortStatus> *currentPortStatus) {
1039     string hpd, pinAssign, linkStatus, vdo;
1040     string path;
1041     AltModeData::DisplayPortAltModeData dpData;
1042 
1043     /*
1044     * We check if the DisplayPort Alt Mode sysfs nodes exist. If they don't, then it means that the
1045     * device has not entered Alt Mode with the port partner because of a source/sink role
1046     * incompatibility, pin assignment incompatibility, etc. So, we then check to see if the partner
1047     * supports Thunderbolt and DisplayPort SVIDs. If it supports DisplayPort, then we assume that
1048     * it must be a source device and Thunderbolt should operate similarly; we don't populate the
1049     * DisplayPortAltModeStatus. If it only supports Thunderbolt, then we cannot determine if it is
1050     * sink or source capable, and need to notify the user.
1051     */
1052     if (usb->getDisplayPortUsbPathHelper(&path) == Status::ERROR) {
1053         std::vector<string> svids;
1054         if (queryPartnerSvids(&svids) == Status::SUCCESS) {
1055             if (std::count(svids.begin(), svids.end(), SVID_THUNDERBOLT) &&
1056                 !std::count(svids.begin(), svids.end(), SVID_DISPLAYPORT)) {
1057                 dpData.cableStatus = DisplayPortAltModeStatus::NOT_CAPABLE;
1058             }
1059         }
1060     } else {
1061         usb->readDisplayPortAttribute("hpd", path, &hpd);
1062         usb->readDisplayPortAttribute("pin_assignment", path, &pinAssign);
1063         usb->readDisplayPortAttribute("vdo", path, &vdo);
1064         usb->readDisplayPortAttribute("link_status", path, &linkStatus);
1065 
1066         dpData = constructAltModeData(hpd, pinAssign, linkStatus, vdo);
1067     }
1068 
1069     (*currentPortStatus)[0].supportedAltModes.push_back(dpData);
1070 
1071     return Status::SUCCESS;
1072 }
1073 
queryUsbDataSession(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)1074 void queryUsbDataSession(android::hardware::usb::Usb *usb,
1075                           std::vector<PortStatus> *currentPortStatus) {
1076     std::vector<ComplianceWarning> warnings;
1077 
1078     usb->mUsbDataSessionMonitor.getComplianceWarnings(
1079         (*currentPortStatus)[0].currentDataRole, &warnings);
1080     (*currentPortStatus)[0].complianceWarnings.insert(
1081         (*currentPortStatus)[0].complianceWarnings.end(),
1082         warnings.begin(),
1083         warnings.end());
1084 }
1085 
queryVersionHelper(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)1086 void queryVersionHelper(android::hardware::usb::Usb *usb,
1087                         std::vector<PortStatus> *currentPortStatus) {
1088     Status status;
1089     string displayPortUsbPath;
1090 
1091     pthread_mutex_lock(&usb->mLock);
1092     status = getPortStatusHelper(usb, currentPortStatus);
1093     queryMoistureDetectionStatus(currentPortStatus);
1094     queryPowerTransferStatus(currentPortStatus);
1095     queryNonCompliantChargerStatus(currentPortStatus);
1096     queryUsbDataSession(usb, currentPortStatus);
1097     pthread_mutex_lock(&usb->mDisplayPortLock);
1098     if (!usb->mDisplayPortFirstSetupDone &&
1099         usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::SUCCESS) {
1100 
1101         ALOGI("usbdp: boot with display connected or usb hal restarted");
1102         usb->setupDisplayPortPoll();
1103     }
1104     pthread_mutex_unlock(&usb->mDisplayPortLock);
1105     queryDisplayPortStatus(usb, currentPortStatus);
1106     if (usb->mCallback != NULL) {
1107         ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
1108             status);
1109         if (!ret.isOk())
1110             ALOGE("queryPortStatus error %s", ret.getDescription().c_str());
1111     } else {
1112         ALOGI("Notifying userspace skipped. Callback is NULL");
1113     }
1114     pthread_mutex_unlock(&usb->mLock);
1115 }
1116 
queryPortStatus(int64_t in_transactionId)1117 ScopedAStatus Usb::queryPortStatus(int64_t in_transactionId) {
1118     std::vector<PortStatus> currentPortStatus;
1119 
1120     queryVersionHelper(this, &currentPortStatus);
1121     pthread_mutex_lock(&mLock);
1122     if (mCallback != NULL) {
1123         ScopedAStatus ret = mCallback->notifyQueryPortStatus(
1124             "all", Status::SUCCESS, in_transactionId);
1125         if (!ret.isOk())
1126             ALOGE("notifyQueryPortStatus error %s", ret.getDescription().c_str());
1127     } else {
1128         ALOGE("Not notifying the userspace. Callback is not set");
1129     }
1130     pthread_mutex_unlock(&mLock);
1131 
1132     return ScopedAStatus::ok();
1133 }
1134 
enableContaminantPresenceDetection(const string & in_portName,bool in_enable,int64_t in_transactionId)1135 ScopedAStatus Usb::enableContaminantPresenceDetection(const string& in_portName,
1136         bool in_enable, int64_t in_transactionId) {
1137     string disable = GetProperty(kDisableContatminantDetection, "");
1138     std::vector<PortStatus> currentPortStatus;
1139     bool success = true;
1140 
1141     if (disable != "true")
1142         success = WriteStringToFile(in_enable ? "1" : "0", enabledPath);
1143 
1144     pthread_mutex_lock(&mLock);
1145     if (mCallback != NULL) {
1146         ScopedAStatus ret = mCallback->notifyContaminantEnabledStatus(
1147             in_portName, in_enable, success ? Status::SUCCESS : Status::ERROR, in_transactionId);
1148         if (!ret.isOk())
1149             ALOGE("notifyContaminantEnabledStatus error %s", ret.getDescription().c_str());
1150     } else {
1151         ALOGE("Not notifying the userspace. Callback is not set");
1152     }
1153     pthread_mutex_unlock(&mLock);
1154 
1155     queryVersionHelper(this, &currentPortStatus);
1156     return ScopedAStatus::ok();
1157 }
1158 
report_overheat_event(android::hardware::usb::Usb * usb)1159 void report_overheat_event(android::hardware::usb::Usb *usb) {
1160     VendorUsbPortOverheat overheat_info;
1161     string contents;
1162 
1163     overheat_info.set_plug_temperature_deci_c(usb->mPluggedTemperatureCelsius * 10);
1164     overheat_info.set_max_temperature_deci_c(usb->mOverheat.getMaxOverheatTemperature() * 10);
1165     if (ReadFileToString(string(kOverheatStatsPath) + "trip_time", &contents)) {
1166         overheat_info.set_time_to_overheat_secs(stoi(Trim(contents)));
1167     } else {
1168         ALOGE("Unable to read trip_time");
1169         return;
1170     }
1171     if (ReadFileToString(string(kOverheatStatsPath) + "hysteresis_time", &contents)) {
1172         overheat_info.set_time_to_hysteresis_secs(stoi(Trim(contents)));
1173     } else {
1174         ALOGE("Unable to read hysteresis_time");
1175         return;
1176     }
1177     if (ReadFileToString(string(kOverheatStatsPath) + "cleared_time", &contents)) {
1178         overheat_info.set_time_to_inactive_secs(stoi(Trim(contents)));
1179     } else {
1180         ALOGE("Unable to read cleared_time");
1181         return;
1182     }
1183 
1184     const shared_ptr<IStats> stats_client = getStatsService();
1185     if (!stats_client) {
1186         ALOGE("Unable to get AIDL Stats service");
1187     } else {
1188         reportUsbPortOverheat(stats_client, overheat_info);
1189     }
1190 }
1191 
1192 struct data {
1193     int uevent_fd;
1194     ::aidl::android::hardware::usb::Usb *usb;
1195 };
1196 
1197 enum UeventType { UNKNOWN, BIND, CHANGE };
1198 
matchUeventType(char * str)1199 enum UeventType matchUeventType(char* str) {
1200     if (!strncmp(str, "ACTION=bind", strlen("ACTION=bind"))) {
1201         return UeventType::BIND;
1202     } else if (!strncmp(str, "ACTION=change", strlen("ACTION=change"))) {
1203         return UeventType::CHANGE;
1204     }
1205     return UeventType::UNKNOWN;
1206 }
1207 
uevent_event(uint32_t,struct data * payload)1208 static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
1209     char msg[UEVENT_MSG_LEN + 2];
1210     char *cp;
1211     int n;
1212     enum UeventType uevent_type = UeventType::UNKNOWN;
1213 
1214     n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
1215     if (n <= 0)
1216         return;
1217     if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
1218         return;
1219 
1220     msg[n] = '\0';
1221     msg[n + 1] = '\0';
1222     cp = msg;
1223 
1224     while (*cp) {
1225         if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
1226             ALOGI("partner added");
1227             pthread_mutex_lock(&payload->usb->mPartnerLock);
1228             payload->usb->mPartnerUp = true;
1229             pthread_cond_signal(&payload->usb->mPartnerCV);
1230             pthread_mutex_unlock(&payload->usb->mPartnerLock);
1231         } else if (std::regex_match(cp, std::regex("(remove)(.*)(-partner)"))) {
1232             string drmDisconnectPath = string(kDisplayPortDrmPath) + "usbc_cable_disconnect";
1233 
1234             if (payload->usb->mPartnerSupportsDisplayPort) {
1235                 ALOGI("displayport partner removed");
1236                 if (!WriteStringToFile("1", drmDisconnectPath)) {
1237                     ALOGE("Failed to signal disconnect to drm");
1238                 }
1239                 payload->usb->mPartnerSupportsDisplayPort = false;
1240             }
1241         } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_")) ||
1242                    !strncmp(cp, "DRIVER=max77759tcpc",
1243                             strlen("DRIVER=max77759tcpc")) ||
1244                    !strncmp(cp, "DRIVER=pogo-transport",
1245                             strlen("DRIVER=pogo-transport")) ||
1246                    !strncmp(cp, "POWER_SUPPLY_NAME=usb",
1247                             strlen("POWER_SUPPLY_NAME=usb"))) {
1248             std::vector<PortStatus> currentPortStatus;
1249             queryVersionHelper(payload->usb, &currentPortStatus);
1250 
1251             // Role switch is not in progress and port is in disconnected state
1252             if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
1253                 for (unsigned long i = 0; i < currentPortStatus.size(); i++) {
1254                     DIR *dp =
1255                         opendir(string("/sys/class/typec/" +
1256                                             string(currentPortStatus[i].portName.c_str()) +
1257                                             "-partner").c_str());
1258                     if (dp == NULL) {
1259                         switchToDrp(currentPortStatus[i].portName);
1260                     } else {
1261                         closedir(dp);
1262                     }
1263                 }
1264                 pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
1265             }
1266             if (!strncmp(cp, "DRIVER=max77759tcpc", strlen("DRIVER=max77759tcpc"))
1267                        && payload->usb->mDisplayPortPollRunning) {
1268                 uint64_t flag = DISPLAYPORT_IRQ_HPD_COUNT_CHECK;
1269 
1270                 ALOGI("usbdp: DISPLAYPORT_IRQ_HPD_COUNT_CHECK sent");
1271                 write(payload->usb->mDisplayPortEventPipe, &flag, sizeof(flag));
1272             }
1273             /*if (!!strncmp(cp, "DEVTYPE=typec_alternate_mode", strlen("DEVTYPE=typec_alternate_mode"))) {
1274                 break;
1275             }*/
1276         } else if (!strncmp(cp, kOverheatStatsDev, strlen(kOverheatStatsDev))) {
1277             ALOGV("Overheat Cooling device suez update");
1278             report_overheat_event(payload->usb);
1279         } else if (!(strncmp(cp, "ACTION=", strlen("ACTION=")))) {
1280             uevent_type = matchUeventType(cp);
1281         } else if (!strncmp(cp, "DRIVER=typec_displayport", strlen("DRIVER=typec_displayport"))) {
1282             if (uevent_type == UeventType::BIND) {
1283                 pthread_mutex_lock(&payload->usb->mDisplayPortLock);
1284                 payload->usb->setupDisplayPortPoll();
1285                 pthread_mutex_unlock(&payload->usb->mDisplayPortLock);
1286             } else if (uevent_type == UeventType::CHANGE) {
1287                 pthread_mutex_lock(&payload->usb->mDisplayPortLock);
1288                 payload->usb->shutdownDisplayPortPoll(false);
1289                 pthread_mutex_unlock(&payload->usb->mDisplayPortLock);
1290             }
1291             break;
1292         }
1293         /* advance to after the next \0 */
1294         while (*cp++) {
1295         }
1296     }
1297 }
1298 
work(void * param)1299 void *work(void *param) {
1300     int epoll_fd, uevent_fd;
1301     struct epoll_event ev;
1302     int nevents = 0;
1303     struct data payload;
1304 
1305     ALOGE("creating thread");
1306 
1307     uevent_fd = uevent_open_socket(64 * 1024, true);
1308 
1309     if (uevent_fd < 0) {
1310         ALOGE("uevent_init: uevent_open_socket failed\n");
1311         return NULL;
1312     }
1313 
1314     payload.uevent_fd = uevent_fd;
1315     payload.usb = (::aidl::android::hardware::usb::Usb *)param;
1316 
1317     fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
1318 
1319     ev.events = EPOLLIN;
1320     ev.data.ptr = (void *)uevent_event;
1321 
1322     epoll_fd = epoll_create(64);
1323     if (epoll_fd == -1) {
1324         ALOGE("epoll_create failed; errno=%d", errno);
1325         goto error;
1326     }
1327 
1328     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
1329         ALOGE("epoll_ctl failed; errno=%d", errno);
1330         goto error;
1331     }
1332 
1333     while (!destroyThread) {
1334         struct epoll_event events[64];
1335 
1336         nevents = epoll_wait(epoll_fd, events, 64, -1);
1337         if (nevents == -1) {
1338             if (errno == EINTR)
1339                 continue;
1340             ALOGE("usb epoll_wait failed; errno=%d", errno);
1341             break;
1342         }
1343 
1344         for (int n = 0; n < nevents; ++n) {
1345             if (events[n].data.ptr)
1346                 (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events,
1347                                                                            &payload);
1348         }
1349     }
1350 
1351     ALOGI("exiting worker thread");
1352 error:
1353     close(uevent_fd);
1354 
1355     if (epoll_fd >= 0)
1356         close(epoll_fd);
1357 
1358     return NULL;
1359 }
1360 
sighandler(int sig)1361 void sighandler(int sig) {
1362     if (sig == SIGUSR1) {
1363         destroyThread = true;
1364         ALOGI("destroy set");
1365         return;
1366     }
1367     signal(SIGUSR1, sighandler);
1368 }
1369 
setCallback(const shared_ptr<IUsbCallback> & in_callback)1370 ScopedAStatus Usb::setCallback(const shared_ptr<IUsbCallback>& in_callback) {
1371     pthread_mutex_lock(&mLock);
1372     if ((mCallback == NULL && in_callback == NULL) ||
1373             (mCallback != NULL && in_callback != NULL)) {
1374         mCallback = in_callback;
1375         pthread_mutex_unlock(&mLock);
1376         return ScopedAStatus::ok();
1377     }
1378 
1379     mCallback = in_callback;
1380     ALOGI("registering callback");
1381 
1382     if (mCallback == NULL) {
1383         if  (!pthread_kill(mPoll, SIGUSR1)) {
1384             pthread_join(mPoll, NULL);
1385             ALOGI("pthread destroyed");
1386         }
1387         pthread_mutex_unlock(&mLock);
1388         return ScopedAStatus::ok();
1389     }
1390 
1391     destroyThread = false;
1392     signal(SIGUSR1, sighandler);
1393 
1394     /*
1395      * Create a background thread if the old callback value is NULL
1396      * and being updated with a new value.
1397      */
1398     if (pthread_create(&mPoll, NULL, work, this)) {
1399         ALOGE("pthread creation failed %d", errno);
1400         mCallback = NULL;
1401     }
1402 
1403     pthread_mutex_unlock(&mLock);
1404     return ScopedAStatus::ok();
1405 }
1406 
1407 /***** DisplayPort Alt Mode Helpers *****/
1408 
getDisplayPortUsbPathHelper(string * path)1409 Status Usb::getDisplayPortUsbPathHelper(string *path) {
1410     DIR *dp;
1411     Status result = Status::ERROR;
1412 
1413     dp = opendir(kDisplayPortUsbPath);
1414     if (dp != NULL) {
1415         struct dirent *ep;
1416         // Iterate through all alt mode directories to find displayport driver
1417         while ((ep = readdir(dp))) {
1418             if (ep->d_type == DT_DIR) {
1419                 DIR *displayPortDp;
1420                 string portPartnerPath = string(kDisplayPortUsbPath) + string(ep->d_name)
1421                         + "/displayport/";
1422                 displayPortDp = opendir(portPartnerPath.c_str());
1423                 if (displayPortDp != NULL) {
1424                     *path = portPartnerPath;
1425                     closedir(displayPortDp);
1426                     result = Status::SUCCESS;
1427                     break;
1428                 }
1429             }
1430         }
1431         closedir(dp);
1432     }
1433     return result;
1434 }
1435 
readDisplayPortAttribute(string attribute,string usb_path,string * value)1436 Status Usb::readDisplayPortAttribute(string attribute, string usb_path, string* value) {
1437     string attrPath;
1438 
1439     if (!strncmp(attribute.c_str(), "hpd", strlen("hpd")) ||
1440         !strncmp(attribute.c_str(), "pin_assignment", strlen("pin_assignment"))) {
1441         attrPath = usb_path + attribute;
1442     } else if (!strncmp(attribute.c_str(), "link_status", strlen("link_status"))) {
1443         attrPath = string(kDisplayPortDrmPath) + "link_status";
1444     } else if (!strncmp(attribute.c_str(), "vdo", strlen("vdo"))) {
1445         attrPath = usb_path + "/../vdo";
1446     } else {
1447         goto error;
1448     }
1449 
1450     // Read Attribute
1451     if(ReadFileToString(attrPath.c_str(), value)) {
1452         return Status::SUCCESS;
1453     }
1454 
1455 error:
1456     ALOGE("usbdp: Failed to read Type-C attribute %s", attribute.c_str());
1457     return Status::ERROR;
1458 }
1459 
writeDisplayPortAttributeOverride(string attribute,string value)1460 Status Usb::writeDisplayPortAttributeOverride(string attribute, string value) {
1461     string attrDrmPath;
1462 
1463     // Get Drm Path
1464     attrDrmPath = string(kDisplayPortDrmPath) + attribute;
1465 
1466     // Write to drm
1467     if(!WriteStringToFile(value, attrDrmPath)) {
1468         ALOGE("usbdp: Failed to write attribute %s to drm: %s", attribute.c_str(), value.c_str());
1469         return Status::ERROR;
1470     }
1471     ALOGI("usbdp: Successfully wrote attribute %s: %s to drm.", attribute.c_str(), value.c_str());
1472     return Status::SUCCESS;
1473 }
1474 
writeDisplayPortAttribute(string attribute,string usb_path)1475 Status Usb::writeDisplayPortAttribute(string attribute, string usb_path) {
1476     string attrUsb, attrDrm, attrDrmPath;
1477 
1478     // Get Drm Path
1479     attrDrmPath = string(kDisplayPortDrmPath) + attribute;
1480 
1481     // Read Attribute
1482     if(!ReadFileToString(usb_path, &attrUsb)) {
1483         ALOGE("usbdp: Failed to open or read Type-C attribute %s", attribute.c_str());
1484         return Status::ERROR;
1485     }
1486 
1487     // Separate Logic for hpd and pin_assignment
1488     if (!strncmp(attribute.c_str(), "hpd", strlen("hpd"))) {
1489         if (!strncmp(attrUsb.c_str(), "0", strlen("0"))) {
1490             // Read DRM attribute to compare
1491             if(!ReadFileToString(attrDrmPath, &attrDrm)) {
1492                 ALOGE("usbdp: Failed to open or read hpd from drm");
1493                 return Status::ERROR;
1494             }
1495             if (!strncmp(attrDrm.c_str(), "0", strlen("0"))) {
1496                 ALOGI("usbdp: Skipping hpd write when drm and usb both equal 0");
1497                 return Status::SUCCESS;
1498             }
1499         }
1500     } else if (!strncmp(attribute.c_str(), "irq_hpd_count", strlen("irq_hpd_count"))) {
1501         uint32_t temp;
1502         if (!::android::base::ParseUint(Trim(attrUsb), &temp)) {
1503             ALOGE("usbdp: failed parsing irq_hpd_count:%s", attrUsb.c_str());
1504             return Status::ERROR;
1505         }
1506         // Used to cache the values read from tcpci's irq_hpd_count.
1507         // Update drm driver when cached value is not the same as the read value.
1508         ALOGI("usbdp: mIrqHpdCountCache:%u irq_hpd_count:%u", mIrqHpdCountCache, temp);
1509         if (mIrqHpdCountCache == temp) {
1510             return Status::SUCCESS;
1511         } else {
1512             mIrqHpdCountCache = temp;
1513         }
1514         attrDrmPath = string(kDisplayPortDrmPath) + "irq_hpd";
1515     } else if (!strncmp(attribute.c_str(), "pin_assignment", strlen("pin_assignment"))) {
1516         size_t pos = attrUsb.find("[");
1517         if (pos != string::npos) {
1518             ALOGI("usbdp: Modifying Pin Config from %s", attrUsb.c_str());
1519             attrUsb = attrUsb.substr(pos+1, 1);
1520         } else {
1521             // Don't write anything
1522             ALOGI("usbdp: Pin config not yet chosen, nothing written.");
1523             return Status::ERROR;
1524         }
1525     }
1526 
1527     // Write to drm
1528     if(!WriteStringToFile(attrUsb, attrDrmPath)) {
1529         ALOGE("usbdp: Failed to write attribute %s to drm: %s", attribute.c_str(), attrUsb.c_str());
1530         return Status::ERROR;
1531     }
1532     ALOGI("usbdp: Successfully wrote attribute %s: %s to drm.", attribute.c_str(), attrUsb.c_str());
1533     return Status::SUCCESS;
1534 }
1535 
determineDisplayPortRetry(string linkPath,string hpdPath)1536 bool Usb::determineDisplayPortRetry(string linkPath, string hpdPath) {
1537     string linkStatus, hpd;
1538 
1539     if(ReadFileToString(linkPath, &linkStatus) && ReadFileToString(hpdPath, &hpd)) {
1540         if (!strncmp(linkStatus.c_str(), "2", strlen("2")) &&
1541                 !strncmp(hpd.c_str(), "1", strlen("1"))) {
1542             return true;
1543         }
1544     }
1545 
1546     return false;
1547 }
1548 
displayPortPollOpenFileHelper(const char * file,int flags)1549 static int displayPortPollOpenFileHelper(const char *file, int flags) {
1550     int fd = open(file, flags);
1551     if (fd == -1) {
1552         ALOGE("usbdp: worker: open at %s failed; errno=%d", file, errno);
1553     }
1554     return fd;
1555 }
1556 
1557 /*
1558  * armTimerFdHelper - Sets timerfd (fd) to trigger after (ms) milliseconds.
1559  * Setting ms to 0 disarms the timer.
1560  */
armTimerFdHelper(int fd,int ms)1561 static int armTimerFdHelper(int fd, int ms) {
1562     struct itimerspec ts;
1563 
1564     ts.it_interval.tv_sec = 0;
1565     ts.it_interval.tv_nsec = 0;
1566     ts.it_value.tv_sec = ms / 1000;
1567     ts.it_value.tv_nsec = (ms % 1000) * 1000000;
1568 
1569     return timerfd_settime(fd, 0, &ts, NULL);
1570 }
1571 
displayPortPollWork(void * param)1572 void *displayPortPollWork(void *param) {
1573     /* USB Payload */
1574     ::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param;
1575     /* Epoll fields */
1576     int epoll_fd;
1577     struct epoll_event ev_hpd, ev_pin, ev_orientation, ev_eventfd, ev_link, ev_debounce;
1578     struct epoll_event ev_activate;
1579     int nevents = 0;
1580     int hpd_fd, pin_fd, orientation_fd, link_training_status_fd;
1581     int file_flags = O_RDONLY;
1582     int epoll_flags;
1583     /* DisplayPort link statuses */
1584     bool orientationSet = false;
1585     bool pinSet = false;
1586     int activateRetryCount = 0;
1587     unsigned long res;
1588     int ret = 0;
1589     /* File paths */
1590     string displayPortUsbPath, irqHpdCountPath, hpdPath, pinAssignmentPath, orientationPath;
1591     string tcpcI2cBus, linkPath, partnerActivePath, portActivePath;
1592 
1593     usb->mDisplayPortPollRunning = true;
1594     usb->mDisplayPortPollStarting = false;
1595 
1596     /*---------- Setup ----------*/
1597 
1598     if (usb->getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::ERROR) {
1599         ALOGE("usbdp: worker: could not locate usb displayport directory");
1600         goto usb_path_error;
1601     }
1602 
1603     ALOGI("usbdp: worker: displayport usb path located at %s", displayPortUsbPath.c_str());
1604     hpdPath = displayPortUsbPath + "hpd";
1605     pinAssignmentPath = displayPortUsbPath + "pin_assignment";
1606     orientationPath = "/sys/class/typec/port0/orientation";
1607     linkPath = string(kDisplayPortDrmPath) + "link_status";
1608 
1609     partnerActivePath = displayPortUsbPath + "../mode1/active";
1610     portActivePath = "/sys/class/typec/port0/port0.0/mode1/active";
1611 
1612     getI2cBusHelper(&tcpcI2cBus);
1613     irqHpdCountPath = kI2CPath + tcpcI2cBus + "/" + tcpcI2cBus + kIrqHpdCounPath;
1614     ALOGI("usbdp: worker: irqHpdCountPath:%s", irqHpdCountPath.c_str());
1615 
1616     epoll_fd = epoll_create(64);
1617     if (epoll_fd == -1) {
1618         ALOGE("usbdp: worker: epoll_create failed; errno=%d", errno);
1619         goto epoll_fd_error;
1620     }
1621 
1622     if ((hpd_fd = displayPortPollOpenFileHelper(hpdPath.c_str(), file_flags)) == -1){
1623         goto hpd_fd_error;
1624     }
1625     if ((pin_fd = displayPortPollOpenFileHelper(pinAssignmentPath.c_str(), file_flags)) == -1){
1626         goto pin_fd_error;
1627     }
1628     if ((orientation_fd = displayPortPollOpenFileHelper(orientationPath.c_str(), file_flags))
1629             == -1){
1630         goto orientation_fd_error;
1631     }
1632     if ((link_training_status_fd = displayPortPollOpenFileHelper(linkPath.c_str(), file_flags)) == -1){
1633         goto link_training_status_fd_error;
1634     }
1635 
1636     // Set epoll_event events and flags
1637     epoll_flags = EPOLLIN | EPOLLET;
1638     ev_hpd.events = epoll_flags;
1639     ev_pin.events = epoll_flags;
1640     ev_orientation.events = epoll_flags;
1641     ev_eventfd.events = epoll_flags;
1642     ev_link.events = epoll_flags;
1643     ev_debounce.events = epoll_flags;
1644     ev_activate.events = epoll_flags;
1645 
1646     ev_hpd.data.fd = hpd_fd;
1647     ev_pin.data.fd = pin_fd;
1648     ev_orientation.data.fd = orientation_fd;
1649     ev_eventfd.data.fd = usb->mDisplayPortEventPipe;
1650     ev_link.data.fd = link_training_status_fd;
1651     ev_debounce.data.fd = usb->mDisplayPortDebounceTimer;
1652     ev_activate.data.fd = usb->mDisplayPortActivateTimer;
1653 
1654     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, hpd_fd, &ev_hpd) == -1) {
1655         ALOGE("usbdp: worker: epoll_ctl failed to add hpd; errno=%d", errno);
1656         goto error;
1657     }
1658     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pin_fd, &ev_pin) == -1) {
1659         ALOGE("usbdp: worker: epoll_ctl failed to add pin; errno=%d", errno);
1660         goto error;
1661     }
1662     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, orientation_fd, &ev_orientation) == -1) {
1663         ALOGE("usbdp: worker: epoll_ctl failed to add orientation; errno=%d", errno);
1664         goto error;
1665     }
1666     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, link_training_status_fd, &ev_link) == -1) {
1667         ALOGE("usbdp: worker: epoll_ctl failed to add link status; errno=%d", errno);
1668         goto error;
1669     }
1670     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortDebounceTimer, &ev_debounce) == -1) {
1671         ALOGE("usbdp: worker: epoll_ctl failed to add framework update debounce; errno=%d", errno);
1672         goto error;
1673     }
1674      if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortActivateTimer, &ev_activate) == -1) {
1675         ALOGE("usbdp: worker: epoll_ctl failed to add activate debounce; errno=%d", errno);
1676         goto error;
1677     }
1678     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, usb->mDisplayPortEventPipe, &ev_eventfd) == -1) {
1679         ALOGE("usbdp: worker: epoll_ctl failed to add orientation; errno=%d", errno);
1680         goto error;
1681     }
1682 
1683     /* Arm timer to see if DisplayPort Alt Mode Activates */
1684     armTimerFdHelper(usb->mDisplayPortActivateTimer, DISPLAYPORT_ACTIVATE_DEBOUNCE_MS);
1685 
1686     while (!destroyDisplayPortThread) {
1687         struct epoll_event events[64];
1688 
1689         nevents = epoll_wait(epoll_fd, events, 64, -1);
1690         if (nevents == -1) {
1691             if (errno == EINTR)
1692                 continue;
1693             ALOGE("usbdp: worker: epoll_wait failed; errno=%d", errno);
1694             break;
1695         }
1696 
1697         for (int n = 0; n < nevents; n++) {
1698             if (events[n].data.fd == hpd_fd) {
1699                 if (!pinSet || !orientationSet) {
1700                     ALOGW("usbdp: worker: HPD may be set before pin_assignment and orientation");
1701                     if (!pinSet &&
1702                         usb->writeDisplayPortAttribute("pin_assignment", pinAssignmentPath) ==
1703                         Status::SUCCESS) {
1704                         pinSet = true;
1705                     }
1706                     if (!orientationSet &&
1707                         usb->writeDisplayPortAttribute("orientation", orientationPath) ==
1708                         Status::SUCCESS) {
1709                         orientationSet = true;
1710                     }
1711                 }
1712                 usb->writeDisplayPortAttribute("hpd", hpdPath);
1713                 armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
1714             } else if (events[n].data.fd == pin_fd) {
1715                 if (usb->writeDisplayPortAttribute("pin_assignment", pinAssignmentPath) ==
1716                     Status::SUCCESS) {
1717                     pinSet = true;
1718                     armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
1719                 }
1720             } else if (events[n].data.fd == orientation_fd) {
1721                 if (usb->writeDisplayPortAttribute("orientation", orientationPath) ==
1722                     Status::SUCCESS) {
1723                     orientationSet = true;
1724                     armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
1725                 }
1726             } else if (events[n].data.fd == link_training_status_fd) {
1727                 armTimerFdHelper(usb->mDisplayPortDebounceTimer, DISPLAYPORT_STATUS_DEBOUNCE_MS);
1728             } else if (events[n].data.fd == usb->mDisplayPortDebounceTimer) {
1729                 std::vector<PortStatus> currentPortStatus;
1730                 ret = read(usb->mDisplayPortDebounceTimer, &res, sizeof(res));
1731                 ALOGI("usbdp: dp debounce triggered, val:%lu ret:%d", res, ret);
1732                 if (ret < 0) {
1733                     ALOGW("usbdp: debounce read error:%d", errno);
1734                     continue;
1735                 }
1736                 queryVersionHelper(usb, &currentPortStatus);
1737             } else if (events[n].data.fd == usb->mDisplayPortActivateTimer) {
1738                 string activePartner, activePort;
1739 
1740                 if (ReadFileToString(partnerActivePath.c_str(), &activePartner) &&
1741                     ReadFileToString(portActivePath.c_str(), &activePort)) {
1742                     // Retry activate signal when DisplayPort Alt Mode is active on port but not
1743                     // partner.
1744                     if (!strncmp(activePartner.c_str(), "no", strlen("no")) &&
1745                         !strncmp(activePort.c_str(), "yes", strlen("yes")) &&
1746                         activateRetryCount < DISPLAYPORT_ACTIVATE_MAX_RETRIES) {
1747                         if (!WriteStringToFile("1", partnerActivePath)) {
1748                             ALOGE("usbdp: Failed to activate port partner Alt Mode");
1749                         } else {
1750                             ALOGI("usbdp: Attempting to activate port partner Alt Mode");
1751                         }
1752                         activateRetryCount++;
1753                         armTimerFdHelper(usb->mDisplayPortActivateTimer,
1754                                          DISPLAYPORT_ACTIVATE_DEBOUNCE_MS);
1755                     } else {
1756                         ALOGI("usbdp: DisplayPort Alt Mode is active, or disabled on port");
1757                     }
1758                 } else {
1759                     activateRetryCount++;
1760                     armTimerFdHelper(usb->mDisplayPortActivateTimer,
1761                                      DISPLAYPORT_ACTIVATE_DEBOUNCE_MS);
1762                     ALOGE("usbdp: Failed to read active state from port or partner");
1763                 }
1764             } else if (events[n].data.fd == usb->mDisplayPortEventPipe) {
1765                 uint64_t flag = 0;
1766                 if (!read(usb->mDisplayPortEventPipe, &flag, sizeof(flag))) {
1767                     if (errno == EAGAIN)
1768                         continue;
1769                     ALOGI("usbdp: worker: Shutdown eventfd read error");
1770                     goto error;
1771                 }
1772                 if (flag == DISPLAYPORT_SHUTDOWN_SET) {
1773                     ALOGI("usbdp: worker: Shutdown eventfd triggered");
1774                     destroyDisplayPortThread = true;
1775                     break;
1776                 } else if (flag == DISPLAYPORT_IRQ_HPD_COUNT_CHECK) {
1777                     ALOGI("usbdp: worker: IRQ_HPD event through DISPLAYPORT_IRQ_HPD_COUNT_CHECK");
1778                     usb->writeDisplayPortAttribute("irq_hpd_count", irqHpdCountPath);
1779                 }
1780             }
1781         }
1782     }
1783 
1784 error:
1785     /* Need to disarm so new threads don't get old event */
1786     armTimerFdHelper(usb->mDisplayPortDebounceTimer, 0);
1787     armTimerFdHelper(usb->mDisplayPortActivateTimer, 0);
1788     close(link_training_status_fd);
1789 link_training_status_fd_error:
1790     close(orientation_fd);
1791 orientation_fd_error:
1792     close(pin_fd);
1793 pin_fd_error:
1794     close(hpd_fd);
1795 hpd_fd_error:
1796     epoll_ctl(epoll_fd, EPOLL_CTL_DEL, usb->mDisplayPortDebounceTimer, &ev_debounce);
1797     epoll_ctl(epoll_fd, EPOLL_CTL_DEL, usb->mDisplayPortActivateTimer, &ev_activate);
1798     epoll_ctl(epoll_fd, EPOLL_CTL_DEL, usb->mDisplayPortEventPipe, &ev_eventfd);
1799     close(epoll_fd);
1800 epoll_fd_error:
1801 usb_path_error:
1802     usb->mDisplayPortPollRunning = false;
1803     ALOGI("usbdp: worker: exiting worker thread");
1804     return NULL;
1805 }
1806 
setTimespecTimer(int debounceMs)1807 static struct timespec setTimespecTimer(int debounceMs) {
1808     struct timespec to;
1809     struct timespec now;
1810 
1811     clock_gettime(CLOCK_MONOTONIC, &now);
1812     to.tv_nsec = now.tv_nsec + ((debounceMs % 1000) * 1000000);
1813     to.tv_sec = now.tv_sec + (debounceMs / 1000);
1814     if (to.tv_nsec >= 1000000000) {
1815         to.tv_nsec -= 1000000000;
1816         to.tv_sec += 1;
1817     }
1818 
1819     return to;
1820 }
1821 
setupDisplayPortPoll()1822 void Usb::setupDisplayPortPoll() {
1823     uint64_t flag = DISPLAYPORT_SHUTDOWN_CLEAR;
1824     mDisplayPortFirstSetupDone = true;
1825     int ret;
1826 
1827     ALOGI("usbdp: setup: beginning setup for displayport poll thread");
1828     mPartnerSupportsDisplayPort = true;
1829 
1830     /*
1831      * If thread is currently starting, then it hasn't setup DisplayPort fd's, and we can abandon
1832      * this process.
1833      */
1834     if (mDisplayPortPollStarting) {
1835         ALOGI("usbdp: setup: abandoning poll thread because another startup is in progress");
1836         return;
1837     }
1838 
1839     /*
1840      * Check to see if thread is currently running. If it is, then we assume that it must have
1841      * invalid DisplayPort fd's and the new thread takes over.
1842      */
1843     if (mDisplayPortPollRunning) {
1844         shutdownDisplayPortPoll(true);
1845         pthread_mutex_lock(&mDisplayPortCVLock);
1846         struct timespec to = setTimespecTimer(DISPLAYPORT_POLL_WAIT_MS);
1847         ret = pthread_cond_timedwait(&mDisplayPortCV, &mDisplayPortCVLock, &to);
1848         if (ret == ETIMEDOUT) {
1849             ALOGI("usbdp: setup: Wait for poll to shutdown timed out, starting new poll anyways.");
1850         }
1851         pthread_mutex_unlock(&mDisplayPortCVLock);
1852     }
1853 
1854     // Indicate that startup procedure is initiated (mutex protects two threads running setup at
1855     // once)
1856     mDisplayPortPollStarting = true;
1857 
1858     // Reset shutdown signals because shutdown() does not perform self clean-up
1859     write(mDisplayPortEventPipe, &flag, sizeof(flag));
1860     destroyDisplayPortThread = false;
1861 
1862     /*
1863      * Create a background thread to poll DisplayPort system files
1864      */
1865     if (pthread_create(&mDisplayPortPoll, NULL, displayPortPollWork, this)) {
1866         ALOGE("usbdp: setup: failed to create displayport poll thread %d", errno);
1867         goto error;
1868     }
1869     ALOGI("usbdp: setup: successfully started displayport poll thread");
1870     return;
1871 
1872 error:
1873     mDisplayPortPollStarting = false;
1874     return;
1875 }
1876 
shutdownDisplayPortPollHelper()1877 void Usb::shutdownDisplayPortPollHelper() {
1878     uint64_t flag = DISPLAYPORT_SHUTDOWN_SET;
1879 
1880     // Write shutdown signal to child thread.
1881     write(mDisplayPortEventPipe, &flag, sizeof(flag));
1882     pthread_join(mDisplayPortPoll, NULL);
1883     writeDisplayPortAttributeOverride("hpd", "0");
1884     pthread_mutex_lock(&mDisplayPortCVLock);
1885     pthread_cond_signal(&mDisplayPortCV);
1886     pthread_mutex_unlock(&mDisplayPortCVLock);
1887 }
1888 
shutdownDisplayPortPollWork(void * param)1889 void *shutdownDisplayPortPollWork(void *param) {
1890     ::aidl::android::hardware::usb::Usb *usb = (::aidl::android::hardware::usb::Usb *)param;
1891 
1892     usb->shutdownDisplayPortPollHelper();
1893     ALOGI("usbdp: shutdown: displayport thread shutdown complete.");
1894     return NULL;
1895 }
1896 
shutdownDisplayPortPoll(bool force)1897 void Usb::shutdownDisplayPortPoll(bool force) {
1898     string displayPortUsbPath;
1899 
1900     ALOGI("usbdp: shutdown: beginning shutdown for displayport poll thread");
1901 
1902     /*
1903      * Determine if should shutdown thread
1904      *
1905      * getDisplayPortUsbPathHelper locates a DisplayPort directory, no need to double check
1906      * directory.
1907      *
1908      * Force is put in place to shutdown even when displayPortUsbPath is still present.
1909      * Happens when back to back BIND events are sent and fds are no longer current.
1910      */
1911     if (!mDisplayPortPollRunning ||
1912         (!force && getDisplayPortUsbPathHelper(&displayPortUsbPath) == Status::SUCCESS)) {
1913         return;
1914     }
1915 
1916     // Shutdown is nonblocking to let other usb operations continue
1917     if (pthread_create(&mDisplayPortShutdownHelper, NULL, shutdownDisplayPortPollWork, this)) {
1918         ALOGE("usbdp: shutdown: shutdown worker pthread creation failed %d", errno);
1919     }
1920 }
1921 
1922 } // namespace usb
1923 } // namespace hardware
1924 } // namespace android
1925 } // aidl
1926