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 <private/android_filesystem_config.h>
27 #include <pthread.h>
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <usbhost/usbhost.h>
32 #include <regex>
33 #include <thread>
34 #include <unordered_map>
35 
36 #include <cutils/uevent.h>
37 #include <sys/epoll.h>
38 #include <utils/Errors.h>
39 #include <utils/StrongPointer.h>
40 #include <utils/Vector.h>
41 
42 #include "Usb.h"
43 
44 #include <aidl/android/frameworks/stats/IStats.h>
45 #include <android_hardware_usb_flags.h>
46 #include <pixelstats/StatsHelper.h>
47 #include <pixelusb/I2cHelper.h>
48 #include <pixelusb/UsbGadgetAidlCommon.h>
49 
50 namespace usb_flags = android::hardware::usb::flags;
51 
52 using aidl::android::frameworks::stats::IStats;
53 using android::base::GetProperty;
54 using android::base::ParseInt;
55 using android::base::Tokenize;
56 using android::base::Trim;
57 using android::hardware::google::pixel::getStatsService;
58 using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat;
59 using android::hardware::google::pixel::reportUsbPortOverheat;
60 using android::hardware::google::pixel::usb::getI2cClientPath;
61 using android::String8;
62 using android::Vector;
63 
64 namespace aidl {
65 namespace android {
66 namespace hardware {
67 namespace usb {
68 // Set by the signal handler to destroy the thread
69 volatile bool destroyThread;
70 
71 string enabledPath;
72 constexpr char kHsi2cPath[] = "/sys/devices/platform/10d60000.hsi2c";
73 constexpr char kTcpcDevName[] = "i2c-max77759tcpc";
74 constexpr char kI2cClientId[] = "0025";
75 constexpr char kComplianceWarningsPath[] = "device/non_compliant_reasons";
76 constexpr char kComplianceWarningBC12[] = "bc12";
77 constexpr char kComplianceWarningDebugAccessory[] = "debug-accessory";
78 constexpr char kComplianceWarningMissingRp[] = "missing_rp";
79 constexpr char kComplianceWarningOther[] = "other";
80 constexpr char kComplianceWarningInputPowerLimited[] = "input_power_limited";
81 constexpr char kContaminantDetectionPath[] = "contaminant_detection";
82 constexpr char kStatusPath[] = "contaminant_detection_status";
83 constexpr char kSinkLimitEnable[] = "usb_limit_sink_enable";
84 constexpr char kSourceLimitEnable[] = "usb_limit_source_enable";
85 constexpr char kSinkLimitCurrent[] = "usb_limit_sink_current";
86 constexpr char kTypecPath[] = "/sys/class/typec";
87 constexpr char kDisableContatminantDetection[] = "vendor.usb.contaminantdisable";
88 constexpr char kOverheatStatsPath[] = "/sys/devices/platform/google,usbc_port_cooling_dev/";
89 constexpr char kOverheatStatsDev[] = "DRIVER=google,usbc_port_cooling_dev";
90 constexpr char kThermalZoneForTrip[] = "VIRTUAL-USB-THROTTLING";
91 constexpr char kThermalZoneForTempReadPrimary[] = "usb_pwr_therm2";
92 constexpr char kThermalZoneForTempReadSecondary1[] = "usb_pwr_therm";
93 constexpr char kThermalZoneForTempReadSecondary2[] = "qi_therm";
94 constexpr char kPogoUsbActive[] = "/sys/devices/platform/google,pogo/pogo_usb_active";
95 constexpr char kPogoEnableHub[] = "/sys/devices/platform/google,pogo/enable_hub";
96 constexpr char kInternalHubDevnum[] = "/sys/bus/usb/devices/1-1/devnum";
97 constexpr char KPogoMoveDataToUsb[] = "/sys/devices/platform/google,pogo/move_data_to_usb";
98 constexpr char kPowerSupplyUsbType[] = "/sys/class/power_supply/usb/usb_type";
99 constexpr char kUdcUeventRegex[] =
100     "/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3";
101 constexpr char kUdcStatePath[] =
102     "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state";
103 constexpr char kHost1UeventRegex[] =
104     "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb2/2-0:1.0";
105 constexpr char kHost1StatePath[] = "/sys/bus/usb/devices/usb2/2-0:1.0/usb2-port1/state";
106 constexpr char kHost2UeventRegex[] =
107     "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb3/3-0:1.0";
108 constexpr char kHost2StatePath[] = "/sys/bus/usb/devices/usb3/3-0:1.0/usb3-port1/state";
109 constexpr char kDataRolePath[] = "/sys/devices/platform/11210000.usb/new_data_role";
110 
111 constexpr int kSamplingIntervalSec = 5;
112 void queryVersionHelper(android::hardware::usb::Usb *usb,
113                         std::vector<PortStatus> *currentPortStatus);
114 
115 #define CTRL_TRANSFER_TIMEOUT_MSEC 1000
116 #define GL852G_VENDOR_ID 0x05e3
117 #define GL852G_PRODUCT_ID1 0x0608
118 #define GL852G_PRODUCT_ID2 0x0610
119 #define GL852G_VENDOR_CMD_REQ 0xe3
120 // GL852G port 1 and port 2 JK level default settings
121 #define GL852G_VENDOR_CMD_VALUE_DEFAULT 0x0008
122 #define GL852G_VENDOR_CMD_INDEX_DEFAULT 0x0404
123 
enableUsbData(const string & in_portName,bool in_enable,int64_t in_transactionId)124 ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable,
125         int64_t in_transactionId) {
126     bool result = true;
127     std::vector<PortStatus> currentPortStatus;
128     string pullup;
129 
130     ALOGI("Userspace turn %s USB data signaling. opID:%ld", in_enable ? "on" : "off",
131             in_transactionId);
132 
133     if (in_enable) {
134         if (!mUsbDataEnabled) {
135             if (ReadFileToString(PULLUP_PATH, &pullup)) {
136                 pullup = Trim(pullup);
137                 if (pullup != kGadgetName) {
138                     if (!WriteStringToFile(kGadgetName, PULLUP_PATH)) {
139                         ALOGE("Gadget cannot be pulled up");
140                         result = false;
141                     }
142                 }
143             }
144 
145             if (!WriteStringToFile("1", USB_DATA_PATH)) {
146                 ALOGE("Not able to turn on usb connection notification");
147                 result = false;
148             }
149         }
150     } else {
151         if (ReadFileToString(PULLUP_PATH, &pullup)) {
152             pullup = Trim(pullup);
153             if (pullup == kGadgetName) {
154                 if (!WriteStringToFile("none", PULLUP_PATH)) {
155                     ALOGE("Gadget cannot be pulled down");
156                     result = false;
157                 }
158             }
159         }
160 
161         if (!WriteStringToFile("1", ID_PATH)) {
162             ALOGE("Not able to turn off host mode");
163             result = false;
164         }
165 
166         if (!WriteStringToFile("0", VBUS_PATH)) {
167             ALOGE("Not able to set Vbus state");
168             result = false;
169         }
170 
171         if (!WriteStringToFile("0", USB_DATA_PATH)) {
172             ALOGE("Not able to turn off usb connection notification");
173             result = false;
174         }
175     }
176 
177     if (result) {
178         mUsbDataEnabled = in_enable;
179     }
180     pthread_mutex_lock(&mLock);
181     if (mCallback != NULL) {
182         ScopedAStatus ret = mCallback->notifyEnableUsbDataStatus(
183             in_portName, in_enable, result ? Status::SUCCESS : Status::ERROR, in_transactionId);
184         if (!ret.isOk())
185             ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
186     } else {
187         ALOGE("Not notifying the userspace. Callback is not set");
188     }
189     pthread_mutex_unlock(&mLock);
190     queryVersionHelper(this, &currentPortStatus);
191 
192     return ScopedAStatus::ok();
193 }
194 
enableUsbDataWhileDocked(const string & in_portName,int64_t in_transactionId)195 ScopedAStatus Usb::enableUsbDataWhileDocked(const string& in_portName,
196         int64_t in_transactionId) {
197     bool success = true;
198     bool notSupported = true;
199     std::vector<PortStatus> currentPortStatus;
200 
201     ALOGI("Userspace enableUsbDataWhileDocked  opID:%ld", in_transactionId);
202 
203     int flags = O_RDONLY;
204     ::android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(KPogoMoveDataToUsb, flags)));
205     if (fd != -1) {
206         notSupported = false;
207         success = WriteStringToFile("1", KPogoMoveDataToUsb);
208         if (!success) {
209             ALOGE("Write to move_data_to_usb failed");
210         }
211     }
212 
213     pthread_mutex_lock(&mLock);
214     if (mCallback != NULL) {
215         ScopedAStatus ret = mCallback->notifyEnableUsbDataWhileDockedStatus(
216                 in_portName, notSupported ? Status::NOT_SUPPORTED :
217                 success ? Status::SUCCESS : Status::ERROR, in_transactionId);
218         if (!ret.isOk())
219             ALOGE("notifyEnableUsbDataStatus error %s", ret.getDescription().c_str());
220     } else {
221         ALOGE("Not notifying the userspace. Callback is not set");
222     }
223     pthread_mutex_unlock(&mLock);
224     queryVersionHelper(this, &currentPortStatus);
225 
226     return ScopedAStatus::ok();
227 }
228 
resetUsbPort(const std::string & in_portName,int64_t in_transactionId)229 ScopedAStatus Usb::resetUsbPort(const std::string& in_portName, int64_t in_transactionId) {
230     bool result = true;
231     std::vector<PortStatus> currentPortStatus;
232 
233     ALOGI("Userspace reset USB Port. opID:%ld", in_transactionId);
234 
235     if (!WriteStringToFile("none", PULLUP_PATH)) {
236         ALOGI("Gadget cannot be pulled down");
237         result = false;
238     }
239 
240     pthread_mutex_lock(&mLock);
241     if (mCallback != NULL) {
242         ::ndk::ScopedAStatus ret = mCallback->notifyResetUsbPortStatus(
243             in_portName, result ? Status::SUCCESS : Status::ERROR, in_transactionId);
244         if (!ret.isOk())
245             ALOGE("notifyTransactionStatus error %s", ret.getDescription().c_str());
246     } else {
247         ALOGE("Not notifying the userspace. Callback is not set");
248     }
249     pthread_mutex_unlock(&mLock);
250 
251     return ::ndk::ScopedAStatus::ok();
252 }
253 
queryMoistureDetectionStatus(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)254 Status queryMoistureDetectionStatus(android::hardware::usb::Usb *usb,
255                                     std::vector<PortStatus> *currentPortStatus) {
256     string enabled, status, DetectedPath;
257 
258     (*currentPortStatus)[0].supportedContaminantProtectionModes
259             .push_back(ContaminantProtectionMode::FORCE_DISABLE);
260     (*currentPortStatus)[0].contaminantProtectionStatus = ContaminantProtectionStatus::NONE;
261     (*currentPortStatus)[0].contaminantDetectionStatus = ContaminantDetectionStatus::DISABLED;
262     (*currentPortStatus)[0].supportsEnableContaminantPresenceDetection = true;
263     (*currentPortStatus)[0].supportsEnableContaminantPresenceProtection = false;
264 
265     if (usb->mI2cClientPath.empty()) {
266         usb->mI2cClientPath = getI2cClientPath(kHsi2cPath, kTcpcDevName, kI2cClientId);
267         if (usb->mI2cClientPath.empty()) {
268             ALOGE("%s: Unable to locate i2c bus node", __func__);
269             return Status::ERROR;
270         }
271     }
272 
273     enabledPath = usb->mI2cClientPath + kContaminantDetectionPath;
274     if (!ReadFileToString(enabledPath, &enabled)) {
275         ALOGE("Failed to open moisture_detection_enabled");
276         return Status::ERROR;
277     }
278 
279     enabled = Trim(enabled);
280     if (enabled == "1") {
281         DetectedPath = usb->mI2cClientPath + kStatusPath;
282         if (!ReadFileToString(DetectedPath, &status)) {
283             ALOGE("Failed to open moisture_detected");
284             return Status::ERROR;
285         }
286         status = Trim(status);
287         if (status == "1") {
288             (*currentPortStatus)[0].contaminantDetectionStatus =
289                 ContaminantDetectionStatus::DETECTED;
290             (*currentPortStatus)[0].contaminantProtectionStatus =
291                 ContaminantProtectionStatus::FORCE_DISABLE;
292         } else {
293             (*currentPortStatus)[0].contaminantDetectionStatus =
294                 ContaminantDetectionStatus::NOT_DETECTED;
295         }
296     }
297 
298     ALOGI("ContaminantDetectionStatus:%d ContaminantProtectionStatus:%d",
299             (*currentPortStatus)[0].contaminantDetectionStatus,
300             (*currentPortStatus)[0].contaminantProtectionStatus);
301 
302     return Status::SUCCESS;
303 }
304 
queryNonCompliantChargerStatus(std::vector<PortStatus> * currentPortStatus)305 Status queryNonCompliantChargerStatus(std::vector<PortStatus> *currentPortStatus) {
306     string reasons, path;
307 
308     for (int i = 0; i < currentPortStatus->size(); i++) {
309         (*currentPortStatus)[i].supportsComplianceWarnings = true;
310         path = string(kTypecPath) + "/" + (*currentPortStatus)[i].portName + "/" +
311                 string(kComplianceWarningsPath);
312         if (ReadFileToString(path.c_str(), &reasons)) {
313             std::vector<string> reasonsList = Tokenize(reasons.c_str(), "[], \n\0");
314             for (string reason : reasonsList) {
315                 if (!strncmp(reason.c_str(), kComplianceWarningDebugAccessory,
316                             strlen(kComplianceWarningDebugAccessory))) {
317                     (*currentPortStatus)[i].complianceWarnings.push_back(ComplianceWarning::DEBUG_ACCESSORY);
318                     continue;
319                 }
320                 if (!strncmp(reason.c_str(), kComplianceWarningBC12,
321                             strlen(kComplianceWarningBC12))) {
322                     (*currentPortStatus)[i].complianceWarnings.push_back(ComplianceWarning::BC_1_2);
323                     continue;
324                 }
325                 if (!strncmp(reason.c_str(), kComplianceWarningMissingRp,
326                             strlen(kComplianceWarningMissingRp))) {
327                     (*currentPortStatus)[i].complianceWarnings.push_back(ComplianceWarning::MISSING_RP);
328                     continue;
329                 }
330                 if (!strncmp(reason.c_str(), kComplianceWarningOther,
331                              strlen(kComplianceWarningOther)) ||
332                     !strncmp(reason.c_str(), kComplianceWarningInputPowerLimited,
333                              strlen(kComplianceWarningInputPowerLimited))) {
334                     if (usb_flags::enable_usb_data_compliance_warning() &&
335                         usb_flags::enable_input_power_limited_warning()) {
336                         ALOGI("Report through INPUT_POWER_LIMITED warning");
337                         (*currentPortStatus)[i].complianceWarnings.push_back(
338                             ComplianceWarning::INPUT_POWER_LIMITED);
339                         continue;
340                     } else {
341                         (*currentPortStatus)[i].complianceWarnings.push_back(
342                             ComplianceWarning::OTHER);
343                         continue;
344                     }
345                 }
346             }
347             if ((*currentPortStatus)[i].complianceWarnings.size() > 0 &&
348                  (*currentPortStatus)[i].currentPowerRole == PortPowerRole::NONE) {
349                 (*currentPortStatus)[i].currentMode = PortMode::UFP;
350                 (*currentPortStatus)[i].currentPowerRole = PortPowerRole::SINK;
351                 (*currentPortStatus)[i].currentDataRole = PortDataRole::NONE;
352                 (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::CONNECTED;
353             }
354         }
355     }
356     return Status::SUCCESS;
357 }
358 
appendRoleNodeHelper(const string & portName,PortRole::Tag tag)359 string appendRoleNodeHelper(const string &portName, PortRole::Tag tag) {
360     string node("/sys/class/typec/" + portName);
361 
362     switch (tag) {
363         case PortRole::dataRole:
364             return node + "/data_role";
365         case PortRole::powerRole:
366             return node + "/power_role";
367         case PortRole::mode:
368             return node + "/port_type";
369         default:
370             return "";
371     }
372 }
373 
convertRoletoString(PortRole role)374 string convertRoletoString(PortRole role) {
375     if (role.getTag() == PortRole::powerRole) {
376         if (role.get<PortRole::powerRole>() == PortPowerRole::SOURCE)
377             return "source";
378         else if (role.get<PortRole::powerRole>() == PortPowerRole::SINK)
379             return "sink";
380     } else if (role.getTag() == PortRole::dataRole) {
381         if (role.get<PortRole::dataRole>() == PortDataRole::HOST)
382             return "host";
383         if (role.get<PortRole::dataRole>() == PortDataRole::DEVICE)
384             return "device";
385     } else if (role.getTag() == PortRole::mode) {
386         if (role.get<PortRole::mode>() == PortMode::UFP)
387             return "sink";
388         if (role.get<PortRole::mode>() == PortMode::DFP)
389             return "source";
390     }
391     return "none";
392 }
393 
extractRole(string * roleName)394 void extractRole(string *roleName) {
395     std::size_t first, last;
396 
397     first = roleName->find("[");
398     last = roleName->find("]");
399 
400     if (first != string::npos && last != string::npos) {
401         *roleName = roleName->substr(first + 1, last - first - 1);
402     }
403 }
404 
switchToDrp(const string & portName)405 void switchToDrp(const string &portName) {
406     string filename = appendRoleNodeHelper(string(portName.c_str()), PortRole::mode);
407     FILE *fp;
408 
409     if (filename != "") {
410         fp = fopen(filename.c_str(), "w");
411         if (fp != NULL) {
412             int ret = fputs("dual", fp);
413             fclose(fp);
414             if (ret == EOF)
415                 ALOGE("Fatal: Error while switching back to drp");
416         } else {
417             ALOGE("Fatal: Cannot open file to switch back to drp");
418         }
419     } else {
420         ALOGE("Fatal: invalid node type");
421     }
422 }
423 
switchMode(const string & portName,const PortRole & in_role,struct Usb * usb)424 bool switchMode(const string &portName, const PortRole &in_role, struct Usb *usb) {
425     string filename = appendRoleNodeHelper(string(portName.c_str()), in_role.getTag());
426     string written;
427     FILE *fp;
428     bool roleSwitch = false;
429 
430     if (filename == "") {
431         ALOGE("Fatal: invalid node type");
432         return false;
433     }
434 
435     fp = fopen(filename.c_str(), "w");
436     if (fp != NULL) {
437         // Hold the lock here to prevent loosing connected signals
438         // as once the file is written the partner added signal
439         // can arrive anytime.
440         pthread_mutex_lock(&usb->mPartnerLock);
441         usb->mPartnerUp = false;
442         int ret = fputs(convertRoletoString(in_role).c_str(), fp);
443         fclose(fp);
444 
445         if (ret != EOF) {
446             struct timespec to;
447             struct timespec now;
448 
449         wait_again:
450             clock_gettime(CLOCK_MONOTONIC, &now);
451             to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
452             to.tv_nsec = now.tv_nsec;
453 
454             int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
455             // There are no uevent signals which implies role swap timed out.
456             if (err == ETIMEDOUT) {
457                 ALOGI("uevents wait timedout");
458                 // Validity check.
459             } else if (!usb->mPartnerUp) {
460                 goto wait_again;
461                 // Role switch succeeded since usb->mPartnerUp is true.
462             } else {
463                 roleSwitch = true;
464             }
465         } else {
466             ALOGI("Role switch failed while wrting to file");
467         }
468         pthread_mutex_unlock(&usb->mPartnerLock);
469     }
470 
471     if (!roleSwitch)
472         switchToDrp(string(portName.c_str()));
473 
474     return roleSwitch;
475 }
476 
getInternalHubUniqueId()477 static int getInternalHubUniqueId() {
478     string internalHubDevnum;
479     int devnum = 0, internalHubUniqueId = -1;
480     if (ReadFileToString(kInternalHubDevnum, &internalHubDevnum) &&
481         ParseInt(Trim(internalHubDevnum).c_str(), &devnum))
482         internalHubUniqueId = 1000 + devnum;
483     return internalHubUniqueId;
484 }
485 
tuneInternalHub(const char * devname,void * client_data)486 static Status tuneInternalHub(const char *devname, void* client_data) {
487     uint16_t vendorId, productId;
488     struct usb_device *device;
489     ::aidl::android::hardware::usb::Usb *usb;
490     int value, index;
491 
492     device = usb_device_open(devname);
493     if (!device) {
494         ALOGE("usb_device_open failed\n");
495         return Status::ERROR;
496     }
497 
498     usb = (::aidl::android::hardware::usb::Usb *)client_data;
499     value = usb->mUsbHubVendorCmdValue;
500     index = usb->mUsbHubVendorCmdIndex;
501 
502     // The vendor cmd only applies to USB Hubs of Genesys Logic, Inc.
503     // The request field of vendor cmd is fixed to 0xe3.
504     vendorId = usb_device_get_vendor_id(device);
505     productId = usb_device_get_product_id(device);
506     if (vendorId == GL852G_VENDOR_ID &&
507         (productId == GL852G_PRODUCT_ID1 || productId == GL852G_PRODUCT_ID2)) {
508         int ret = usb_device_control_transfer(device,
509             USB_DIR_OUT | USB_TYPE_VENDOR, GL852G_VENDOR_CMD_REQ, value, index,
510             NULL, 0, CTRL_TRANSFER_TIMEOUT_MSEC);
511         ALOGI("USB hub vendor cmd %s (wValue 0x%x, wIndex 0x%x, return %d)\n",
512                 ret? "failed" : "succeeded", value, index, ret);
513     }
514 
515     usb_device_close(device);
516 
517     return Status::SUCCESS;
518 }
519 
usbDeviceRemoved(const char * devname,void * client_data)520 static int usbDeviceRemoved(const char *devname, void* client_data) {
521     return 0;
522 }
523 
usbDeviceAdded(const char * devname,void * client_data)524 static int usbDeviceAdded(const char *devname, void* client_data) {
525     string pogoEnableHub;
526     int uniqueId = 0;
527 
528     // Enable hub tuning when the pogo dock is connected.
529     if (ReadFileToString(kPogoEnableHub, &pogoEnableHub) && Trim(pogoEnableHub) == "1") {
530         // If enable_hub is set to 1, the internal hub is the first enumearted device on bus 1 and
531         // port 1.
532         uniqueId = usb_device_get_unique_id_from_name(devname);
533         if (uniqueId == getInternalHubUniqueId())
534             tuneInternalHub(devname, client_data);
535     }
536 
537     return 0;
538 }
539 
usbHostWork(void * param)540 void *usbHostWork(void *param) {
541     struct usb_host_context *ctx;
542 
543     ALOGI("creating USB host thread\n");
544 
545     ctx = usb_host_init();
546     if (!ctx) {
547         ALOGE("usb_host_init failed\n");
548         return NULL;
549     }
550 
551     // This will never return, it will keep monitoring USB sysfs inotify events
552     usb_host_run(ctx, usbDeviceAdded, usbDeviceRemoved, NULL, param);
553 
554     return NULL;
555 }
556 
updatePortStatus(android::hardware::usb::Usb * usb)557 void updatePortStatus(android::hardware::usb::Usb *usb) {
558     std::vector<PortStatus> currentPortStatus;
559 
560     queryVersionHelper(usb, &currentPortStatus);
561 }
562 
Usb()563 Usb::Usb()
564     : mLock(PTHREAD_MUTEX_INITIALIZER),
565       mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
566       mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
567       mPartnerUp(false),
568       mUsbDataSessionMonitor(kUdcUeventRegex, kUdcStatePath, kHost1UeventRegex, kHost1StatePath,
569                              kHost2UeventRegex, kHost2StatePath, kDataRolePath,
570                              std::bind(&updatePortStatus, this)),
571       mOverheat(ZoneInfo(TemperatureType::USB_PORT, kThermalZoneForTrip,
572                          ThrottlingSeverity::CRITICAL),
573                 {ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadPrimary,
574                           ThrottlingSeverity::NONE),
575                  ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary1,
576                           ThrottlingSeverity::NONE),
577                  ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadSecondary2,
578                           ThrottlingSeverity::NONE)}, kSamplingIntervalSec),
579       mUsbDataEnabled(true),
580       mUsbHubVendorCmdValue(GL852G_VENDOR_CMD_VALUE_DEFAULT),
581       mUsbHubVendorCmdIndex(GL852G_VENDOR_CMD_INDEX_DEFAULT),
582       mI2cClientPath("") {
583     pthread_condattr_t attr;
584     if (pthread_condattr_init(&attr)) {
585         ALOGE("pthread_condattr_init failed: %s", strerror(errno));
586         abort();
587     }
588     if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
589         ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
590         abort();
591     }
592     if (pthread_cond_init(&mPartnerCV, &attr)) {
593         ALOGE("pthread_cond_init failed: %s", strerror(errno));
594         abort();
595     }
596     if (pthread_condattr_destroy(&attr)) {
597         ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
598         abort();
599     }
600     if (pthread_create(&mUsbHost, NULL, usbHostWork, this)) {
601         ALOGE("pthread creation failed %d\n", errno);
602         abort();
603     }
604 
605     ALOGI("feature flag enable_usb_data_compliance_warning: %d",
606           usb_flags::enable_usb_data_compliance_warning());
607     ALOGI("feature flag enable_input_power_limited_warning: %d",
608           usb_flags::enable_input_power_limited_warning());
609 }
610 
switchRole(const string & in_portName,const PortRole & in_role,int64_t in_transactionId)611 ScopedAStatus Usb::switchRole(const string& in_portName, const PortRole& in_role,
612         int64_t in_transactionId) {
613     string filename = appendRoleNodeHelper(string(in_portName.c_str()), in_role.getTag());
614     string written;
615     FILE *fp;
616     bool roleSwitch = false;
617 
618     if (filename == "") {
619         ALOGE("Fatal: invalid node type");
620         return ScopedAStatus::ok();
621     }
622 
623     pthread_mutex_lock(&mRoleSwitchLock);
624 
625     ALOGI("filename write: %s role:%s", filename.c_str(), convertRoletoString(in_role).c_str());
626 
627     if (in_role.getTag() == PortRole::mode) {
628         roleSwitch = switchMode(in_portName, in_role, this);
629     } else {
630         fp = fopen(filename.c_str(), "w");
631         if (fp != NULL) {
632             int ret = fputs(convertRoletoString(in_role).c_str(), fp);
633             if (ret == EAGAIN) {
634                 ALOGI("role switch busy, retry in %d ms", ROLE_SWAP_RETRY_MS);
635                 std::this_thread::sleep_for(std::chrono::milliseconds(ROLE_SWAP_RETRY_MS));
636                 ret = fputs(convertRoletoString(in_role).c_str(), fp);
637             }
638             fclose(fp);
639             if ((ret != EOF) && ReadFileToString(filename, &written)) {
640                 written = Trim(written);
641                 extractRole(&written);
642                 ALOGI("written: %s", written.c_str());
643                 if (written == convertRoletoString(in_role)) {
644                     roleSwitch = true;
645                 } else {
646                     ALOGE("Role switch failed");
647                 }
648             } else {
649                 ALOGE("failed to update the new role");
650             }
651         } else {
652             ALOGE("fopen failed");
653         }
654     }
655 
656     pthread_mutex_lock(&mLock);
657     if (mCallback != NULL) {
658          ScopedAStatus ret = mCallback->notifyRoleSwitchStatus(
659             in_portName, in_role, roleSwitch ? Status::SUCCESS : Status::ERROR, in_transactionId);
660         if (!ret.isOk())
661             ALOGE("RoleSwitchStatus error %s", ret.getDescription().c_str());
662     } else {
663         ALOGE("Not notifying the userspace. Callback is not set");
664     }
665     pthread_mutex_unlock(&mLock);
666     pthread_mutex_unlock(&mRoleSwitchLock);
667 
668     return ScopedAStatus::ok();
669 }
670 
limitPowerTransfer(const string & in_portName,bool in_limit,int64_t in_transactionId)671 ScopedAStatus Usb::limitPowerTransfer(const string& in_portName, bool in_limit,
672         int64_t in_transactionId) {
673     bool sessionFail = false, success;
674     std::vector<PortStatus> currentPortStatus;
675     string sinkLimitEnablePath, currentLimitPath, sourceLimitEnablePath;
676 
677     if (mI2cClientPath.empty()) {
678         mI2cClientPath = getI2cClientPath(kHsi2cPath, kTcpcDevName, kI2cClientId);
679         if (mI2cClientPath.empty()) {
680             ALOGE("%s: Unable to locate i2c bus node", __func__);
681             return ScopedAStatus::ok();
682         }
683     }
684 
685     sinkLimitEnablePath = mI2cClientPath + kSinkLimitEnable;
686     currentLimitPath = mI2cClientPath + kSinkLimitCurrent;
687     sourceLimitEnablePath = mI2cClientPath + kSourceLimitEnable;
688 
689     pthread_mutex_lock(&mLock);
690     if (in_limit) {
691         success = WriteStringToFile("0", currentLimitPath);
692         if (!success) {
693             ALOGE("Failed to set sink current limit");
694             sessionFail = true;
695         }
696     }
697     success = WriteStringToFile(in_limit ? "1" : "0", sinkLimitEnablePath);
698     if (!success) {
699         ALOGE("Failed to %s sink current limit: %s", in_limit ? "enable" : "disable",
700               sinkLimitEnablePath.c_str());
701         sessionFail = true;
702     }
703     success = WriteStringToFile(in_limit ? "1" : "0", sourceLimitEnablePath);
704     if (!success) {
705         ALOGE("Failed to %s source current limit: %s", in_limit ? "enable" : "disable",
706               sourceLimitEnablePath.c_str());
707         sessionFail = true;
708     }
709 
710     ALOGI("limitPowerTransfer limit:%c opId:%ld", in_limit ? 'y' : 'n', in_transactionId);
711     if (mCallback != NULL && in_transactionId >= 0) {
712         ScopedAStatus ret = mCallback->notifyLimitPowerTransferStatus(
713                 in_portName, in_limit, sessionFail ? Status::ERROR : Status::SUCCESS,
714                 in_transactionId);
715         if (!ret.isOk())
716             ALOGE("limitPowerTransfer error %s", ret.getDescription().c_str());
717     } else {
718         ALOGE("Not notifying the userspace. Callback is not set");
719     }
720 
721     pthread_mutex_unlock(&mLock);
722     queryVersionHelper(this, &currentPortStatus);
723 
724     return ScopedAStatus::ok();
725 }
726 
queryPowerTransferStatus(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)727 Status queryPowerTransferStatus(android::hardware::usb::Usb *usb,
728                                 std::vector<PortStatus> *currentPortStatus) {
729     string limitedPath, enabled;
730 
731     if (usb->mI2cClientPath.empty()) {
732         usb->mI2cClientPath = getI2cClientPath(kHsi2cPath, kTcpcDevName, kI2cClientId);
733         if (usb->mI2cClientPath.empty()) {
734             ALOGE("%s: Unable to locate i2c bus node", __func__);
735             return Status::ERROR;
736         }
737     }
738 
739     limitedPath = usb->mI2cClientPath + kSinkLimitEnable;
740     if (!ReadFileToString(limitedPath, &enabled)) {
741         ALOGE("Failed to open limit_sink_enable");
742         return Status::ERROR;
743     }
744 
745     enabled = Trim(enabled);
746     (*currentPortStatus)[0].powerTransferLimited = enabled == "1";
747 
748     ALOGI("powerTransferLimited:%d", (*currentPortStatus)[0].powerTransferLimited ? 1 : 0);
749     return Status::SUCCESS;
750 }
751 
getAccessoryConnected(const string & portName,string * accessory)752 Status getAccessoryConnected(const string &portName, string *accessory) {
753     string filename = "/sys/class/typec/" + portName + "-partner/accessory_mode";
754 
755     if (!ReadFileToString(filename, accessory)) {
756         ALOGE("getAccessoryConnected: Failed to open filesystem node: %s", filename.c_str());
757         return Status::ERROR;
758     }
759     *accessory = Trim(*accessory);
760 
761     return Status::SUCCESS;
762 }
763 
getCurrentRoleHelper(const string & portName,bool connected,PortRole * currentRole)764 Status getCurrentRoleHelper(const string &portName, bool connected, PortRole *currentRole) {
765     string filename;
766     string roleName;
767     string accessory;
768 
769     // Mode
770 
771     if (currentRole->getTag() == PortRole::powerRole) {
772         filename = "/sys/class/typec/" + portName + "/power_role";
773         currentRole->set<PortRole::powerRole>(PortPowerRole::NONE);
774     } else if (currentRole->getTag() == PortRole::dataRole) {
775         filename = "/sys/class/typec/" + portName + "/data_role";
776         currentRole->set<PortRole::dataRole>(PortDataRole::NONE);
777     } else if (currentRole->getTag() == PortRole::mode) {
778         filename = "/sys/class/typec/" + portName + "/data_role";
779         currentRole->set<PortRole::mode>(PortMode::NONE);
780     } else {
781         return Status::ERROR;
782     }
783 
784     if (!connected)
785         return Status::SUCCESS;
786 
787     if (currentRole->getTag() == PortRole::mode) {
788         if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
789             return Status::ERROR;
790         }
791         if (accessory == "analog_audio") {
792             currentRole->set<PortRole::mode>(PortMode::AUDIO_ACCESSORY);
793             return Status::SUCCESS;
794         } else if (accessory == "debug") {
795             currentRole->set<PortRole::mode>(PortMode::DEBUG_ACCESSORY);
796             return Status::SUCCESS;
797         }
798     }
799 
800     if (!ReadFileToString(filename, &roleName)) {
801         ALOGE("getCurrentRole: Failed to open filesystem node: %s", filename.c_str());
802         return Status::ERROR;
803     }
804 
805     roleName = Trim(roleName);
806     extractRole(&roleName);
807 
808     if (roleName == "source") {
809         currentRole->set<PortRole::powerRole>(PortPowerRole::SOURCE);
810     } else if (roleName == "sink") {
811         currentRole->set<PortRole::powerRole>(PortPowerRole::SINK);
812     } else if (roleName == "host") {
813         if (currentRole->getTag() == PortRole::dataRole)
814             currentRole->set<PortRole::dataRole>(PortDataRole::HOST);
815         else
816             currentRole->set<PortRole::mode>(PortMode::DFP);
817     } else if (roleName == "device") {
818         if (currentRole->getTag() == PortRole::dataRole)
819             currentRole->set<PortRole::dataRole>(PortDataRole::DEVICE);
820         else
821             currentRole->set<PortRole::mode>(PortMode::UFP);
822     } else if (roleName != "none") {
823         /* case for none has already been addressed.
824          * so we check if the role isn't none.
825          */
826         return Status::UNRECOGNIZED_ROLE;
827     }
828     return Status::SUCCESS;
829 }
830 
getTypeCPortNamesHelper(std::unordered_map<string,bool> * names)831 Status getTypeCPortNamesHelper(std::unordered_map<string, bool> *names) {
832     DIR *dp;
833 
834     dp = opendir(kTypecPath);
835     if (dp != NULL) {
836         struct dirent *ep;
837 
838         while ((ep = readdir(dp))) {
839             if (ep->d_type == DT_LNK) {
840                 if (string::npos == string(ep->d_name).find("-partner")) {
841                     std::unordered_map<string, bool>::const_iterator portName =
842                         names->find(ep->d_name);
843                     if (portName == names->end()) {
844                         names->insert({ep->d_name, false});
845                     }
846                 } else {
847                     (*names)[std::strtok(ep->d_name, "-")] = true;
848                 }
849             }
850         }
851         closedir(dp);
852         return Status::SUCCESS;
853     }
854 
855     ALOGE("Failed to open /sys/class/typec");
856     return Status::ERROR;
857 }
858 
canSwitchRoleHelper(const string & portName)859 bool canSwitchRoleHelper(const string &portName) {
860     string filename = "/sys/class/typec/" + portName + "-partner/supports_usb_power_delivery";
861     string supportsPD;
862 
863     if (ReadFileToString(filename, &supportsPD)) {
864         supportsPD = Trim(supportsPD);
865         if (supportsPD == "yes") {
866             return true;
867         }
868     }
869 
870     return false;
871 }
872 
getPortStatusHelper(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)873 Status getPortStatusHelper(android::hardware::usb::Usb *usb,
874         std::vector<PortStatus> *currentPortStatus) {
875     std::unordered_map<string, bool> names;
876     Status result = getTypeCPortNamesHelper(&names);
877     int i = -1;
878 
879     if (result == Status::SUCCESS) {
880         currentPortStatus->resize(names.size());
881         for (std::pair<string, bool> port : names) {
882             i++;
883             ALOGI("%s", port.first.c_str());
884             (*currentPortStatus)[i].portName = port.first;
885 
886             PortRole currentRole;
887             currentRole.set<PortRole::powerRole>(PortPowerRole::NONE);
888             if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
889                 (*currentPortStatus)[i].currentPowerRole = currentRole.get<PortRole::powerRole>();
890             } else {
891                 ALOGE("Error while retrieving portNames");
892                 goto done;
893             }
894 
895             currentRole.set<PortRole::dataRole>(PortDataRole::NONE);
896             if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
897                 (*currentPortStatus)[i].currentDataRole = currentRole.get<PortRole::dataRole>();
898             } else {
899                 ALOGE("Error while retrieving current port role");
900                 goto done;
901             }
902 
903             currentRole.set<PortRole::mode>(PortMode::NONE);
904             if (getCurrentRoleHelper(port.first, port.second, &currentRole) == Status::SUCCESS) {
905                 (*currentPortStatus)[i].currentMode = currentRole.get<PortRole::mode>();
906             } else {
907                 ALOGE("Error while retrieving current data role");
908                 goto done;
909             }
910 
911             (*currentPortStatus)[i].canChangeMode = true;
912             (*currentPortStatus)[i].canChangeDataRole =
913                 port.second ? canSwitchRoleHelper(port.first) : false;
914             (*currentPortStatus)[i].canChangePowerRole =
915                 port.second ? canSwitchRoleHelper(port.first) : false;
916 
917             (*currentPortStatus)[i].supportedModes.push_back(PortMode::DRP);
918 
919             bool dataEnabled = true;
920             string pogoUsbActive = "0";
921             if (ReadFileToString(string(kPogoUsbActive), &pogoUsbActive) &&
922                 stoi(Trim(pogoUsbActive)) == 1) {
923                 /*
924                  * Always signal USB device mode disabled irrespective of hub enabled while docked.
925                  * Hub gets automatically enabled as needed. Signalling DISABLED_DOCK_HOST_MODE &
926                  * DEVICE_MODE during pogo direct can cause notifications to show for brief windows
927                  * when the state machine is still moving to steady state.
928                  */
929                 (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::DISABLED_DOCK_DEVICE_MODE);
930                 dataEnabled = false;
931             }
932             if (!usb->mUsbDataEnabled) {
933                 (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::DISABLED_FORCE);
934                 dataEnabled = false;
935             }
936             if (dataEnabled) {
937                 (*currentPortStatus)[i].usbDataStatus.push_back(UsbDataStatus::ENABLED);
938             }
939 
940             // When connected return powerBrickStatus
941             if (port.second) {
942                 string usbType;
943                 if ((*currentPortStatus)[i].currentPowerRole == PortPowerRole::SOURCE) {
944                     (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::NOT_CONNECTED;
945                 } else if (ReadFileToString(string(kPowerSupplyUsbType), &usbType)) {
946                     if (strstr(usbType.c_str(), "[D")) {
947                         (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::CONNECTED;
948                     } else if (strstr(usbType.c_str(), "[U")) {
949                         (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::UNKNOWN;
950                     } else {
951                         (*currentPortStatus)[i].powerBrickStatus =
952                                 PowerBrickStatus::NOT_CONNECTED;
953                     }
954                 } else {
955                     ALOGE("Error while reading usb_type");
956                 }
957             } else {
958                 (*currentPortStatus)[i].powerBrickStatus = PowerBrickStatus::NOT_CONNECTED;
959             }
960 
961             ALOGI("%d:%s connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d "
962                   "usbDataEnabled:%d",
963                 i, port.first.c_str(), port.second,
964                 (*currentPortStatus)[i].canChangeMode,
965                 (*currentPortStatus)[i].canChangeDataRole,
966                 (*currentPortStatus)[i].canChangePowerRole,
967                 dataEnabled ? 1 : 0);
968         }
969 
970         return Status::SUCCESS;
971     }
972 done:
973     return Status::ERROR;
974 }
975 
queryUsbDataSession(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)976 void queryUsbDataSession(android::hardware::usb::Usb *usb,
977                           std::vector<PortStatus> *currentPortStatus) {
978     std::vector<ComplianceWarning> warnings;
979 
980     usb->mUsbDataSessionMonitor.getComplianceWarnings(
981         (*currentPortStatus)[0].currentDataRole, &warnings);
982     (*currentPortStatus)[0].complianceWarnings.insert(
983         (*currentPortStatus)[0].complianceWarnings.end(),
984         warnings.begin(),
985         warnings.end());
986 }
987 
queryVersionHelper(android::hardware::usb::Usb * usb,std::vector<PortStatus> * currentPortStatus)988 void queryVersionHelper(android::hardware::usb::Usb *usb,
989                         std::vector<PortStatus> *currentPortStatus) {
990     Status status;
991     pthread_mutex_lock(&usb->mLock);
992     status = getPortStatusHelper(usb, currentPortStatus);
993     if (status == Status::SUCCESS && currentPortStatus->size() > 0) {
994         queryMoistureDetectionStatus(usb, currentPortStatus);
995         queryPowerTransferStatus(usb, currentPortStatus);
996         queryNonCompliantChargerStatus(currentPortStatus);
997         queryUsbDataSession(usb, currentPortStatus);
998         if (usb->mCallback != NULL) {
999             ScopedAStatus ret = usb->mCallback->notifyPortStatusChange(*currentPortStatus,
1000                 status);
1001             if (!ret.isOk())
1002                 ALOGE("queryPortStatus error %s", ret.getDescription().c_str());
1003         } else {
1004             ALOGI("Notifying userspace skipped. Callback is NULL");
1005         }
1006     } else {
1007         ALOGI("%s skipped. currentPortStatus is empty", __func__);
1008     }
1009     pthread_mutex_unlock(&usb->mLock);
1010 }
1011 
queryPortStatus(int64_t in_transactionId)1012 ScopedAStatus Usb::queryPortStatus(int64_t in_transactionId) {
1013     std::vector<PortStatus> currentPortStatus;
1014 
1015     queryVersionHelper(this, &currentPortStatus);
1016     pthread_mutex_lock(&mLock);
1017     if (mCallback != NULL) {
1018         ScopedAStatus ret = mCallback->notifyQueryPortStatus(
1019             "all", Status::SUCCESS, in_transactionId);
1020         if (!ret.isOk())
1021             ALOGE("notifyQueryPortStatus error %s", ret.getDescription().c_str());
1022     } else {
1023         ALOGE("Not notifying the userspace. Callback is not set");
1024     }
1025     pthread_mutex_unlock(&mLock);
1026 
1027     return ScopedAStatus::ok();
1028 }
1029 
enableContaminantPresenceDetection(const string & in_portName,bool in_enable,int64_t in_transactionId)1030 ScopedAStatus Usb::enableContaminantPresenceDetection(const string& in_portName,
1031         bool in_enable, int64_t in_transactionId) {
1032     string disable = GetProperty(kDisableContatminantDetection, "");
1033     std::vector<PortStatus> currentPortStatus;
1034     bool success = true;
1035 
1036     if (disable != "true")
1037         success = WriteStringToFile(in_enable ? "1" : "0", enabledPath);
1038 
1039     pthread_mutex_lock(&mLock);
1040     if (mCallback != NULL) {
1041         ScopedAStatus ret = mCallback->notifyContaminantEnabledStatus(
1042             in_portName, in_enable, success ? Status::SUCCESS : Status::ERROR, in_transactionId);
1043         if (!ret.isOk())
1044             ALOGE("notifyContaminantEnabledStatus error %s", ret.getDescription().c_str());
1045     } else {
1046         ALOGE("Not notifying the userspace. Callback is not set");
1047     }
1048     pthread_mutex_unlock(&mLock);
1049 
1050     queryVersionHelper(this, &currentPortStatus);
1051     return ScopedAStatus::ok();
1052 }
1053 
report_overheat_event(android::hardware::usb::Usb * usb)1054 void report_overheat_event(android::hardware::usb::Usb *usb) {
1055     VendorUsbPortOverheat overheat_info;
1056     string contents;
1057 
1058     overheat_info.set_plug_temperature_deci_c(usb->mPluggedTemperatureCelsius * 10);
1059     overheat_info.set_max_temperature_deci_c(usb->mOverheat.getMaxOverheatTemperature() * 10);
1060     if (ReadFileToString(string(kOverheatStatsPath) + "trip_time", &contents)) {
1061         overheat_info.set_time_to_overheat_secs(stoi(Trim(contents)));
1062     } else {
1063         ALOGE("Unable to read trip_time");
1064         return;
1065     }
1066     if (ReadFileToString(string(kOverheatStatsPath) + "hysteresis_time", &contents)) {
1067         overheat_info.set_time_to_hysteresis_secs(stoi(Trim(contents)));
1068     } else {
1069         ALOGE("Unable to read hysteresis_time");
1070         return;
1071     }
1072     if (ReadFileToString(string(kOverheatStatsPath) + "cleared_time", &contents)) {
1073         overheat_info.set_time_to_inactive_secs(stoi(Trim(contents)));
1074     } else {
1075         ALOGE("Unable to read cleared_time");
1076         return;
1077     }
1078 
1079     const shared_ptr<IStats> stats_client = getStatsService();
1080     if (!stats_client) {
1081         ALOGE("Unable to get AIDL Stats service");
1082     } else {
1083         reportUsbPortOverheat(stats_client, overheat_info);
1084     }
1085 }
1086 
1087 struct data {
1088     int uevent_fd;
1089     ::aidl::android::hardware::usb::Usb *usb;
1090 };
1091 
uevent_event(uint32_t,struct data * payload)1092 static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
1093     char msg[UEVENT_MSG_LEN + 2];
1094     char *cp;
1095     int n;
1096 
1097     n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
1098     if (n <= 0)
1099         return;
1100     if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
1101         return;
1102 
1103     msg[n] = '\0';
1104     msg[n + 1] = '\0';
1105     cp = msg;
1106 
1107     while (*cp) {
1108         if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
1109             ALOGI("partner added");
1110             pthread_mutex_lock(&payload->usb->mPartnerLock);
1111             payload->usb->mPartnerUp = true;
1112             pthread_cond_signal(&payload->usb->mPartnerCV);
1113             pthread_mutex_unlock(&payload->usb->mPartnerLock);
1114         } else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_")) ||
1115                    !strncmp(cp, "DRIVER=max77759tcpc",
1116                             strlen("DRIVER=max77759tcpc")) ||
1117                    !strncmp(cp, "DRIVER=pogo-transport",
1118                             strlen("DRIVER=pogo-transport")) ||
1119                    !strncmp(cp, "POWER_SUPPLY_NAME=usb",
1120                             strlen("POWER_SUPPLY_NAME=usb"))) {
1121             std::vector<PortStatus> currentPortStatus;
1122             queryVersionHelper(payload->usb, &currentPortStatus);
1123 
1124             // Role switch is not in progress and port is in disconnected state
1125             if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
1126                 for (unsigned long i = 0; i < currentPortStatus.size(); i++) {
1127                     DIR *dp =
1128                         opendir(string("/sys/class/typec/" +
1129                                             string(currentPortStatus[i].portName.c_str()) +
1130                                             "-partner").c_str());
1131                     if (dp == NULL) {
1132                         switchToDrp(currentPortStatus[i].portName);
1133                     } else {
1134                         closedir(dp);
1135                     }
1136                 }
1137                 pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
1138             }
1139             break;
1140         } else if (!strncmp(cp, kOverheatStatsDev, strlen(kOverheatStatsDev))) {
1141             ALOGV("Overheat Cooling device suez update");
1142             report_overheat_event(payload->usb);
1143         }
1144         /* advance to after the next \0 */
1145         while (*cp++) {
1146         }
1147     }
1148 }
1149 
work(void * param)1150 void *work(void *param) {
1151     int epoll_fd, uevent_fd;
1152     struct epoll_event ev;
1153     int nevents = 0;
1154     struct data payload;
1155 
1156     ALOGE("creating thread");
1157 
1158     uevent_fd = uevent_open_socket(64 * 1024, true);
1159 
1160     if (uevent_fd < 0) {
1161         ALOGE("uevent_init: uevent_open_socket failed\n");
1162         return NULL;
1163     }
1164 
1165     payload.uevent_fd = uevent_fd;
1166     payload.usb = (::aidl::android::hardware::usb::Usb *)param;
1167 
1168     fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
1169 
1170     ev.events = EPOLLIN;
1171     ev.data.ptr = (void *)uevent_event;
1172 
1173     epoll_fd = epoll_create(64);
1174     if (epoll_fd == -1) {
1175         ALOGE("epoll_create failed; errno=%d", errno);
1176         goto error;
1177     }
1178 
1179     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
1180         ALOGE("epoll_ctl failed; errno=%d", errno);
1181         goto error;
1182     }
1183 
1184     while (!destroyThread) {
1185         struct epoll_event events[64];
1186 
1187         nevents = epoll_wait(epoll_fd, events, 64, -1);
1188         if (nevents == -1) {
1189             if (errno == EINTR)
1190                 continue;
1191             ALOGE("usb epoll_wait failed; errno=%d", errno);
1192             break;
1193         }
1194 
1195         for (int n = 0; n < nevents; ++n) {
1196             if (events[n].data.ptr)
1197                 (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events,
1198                                                                            &payload);
1199         }
1200     }
1201 
1202     ALOGI("exiting worker thread");
1203 error:
1204     close(uevent_fd);
1205 
1206     if (epoll_fd >= 0)
1207         close(epoll_fd);
1208 
1209     return NULL;
1210 }
1211 
sighandler(int sig)1212 void sighandler(int sig) {
1213     if (sig == SIGUSR1) {
1214         destroyThread = true;
1215         ALOGI("destroy set");
1216         return;
1217     }
1218     signal(SIGUSR1, sighandler);
1219 }
1220 
setCallback(const shared_ptr<IUsbCallback> & in_callback)1221 ScopedAStatus Usb::setCallback(const shared_ptr<IUsbCallback>& in_callback) {
1222     pthread_mutex_lock(&mLock);
1223     if ((mCallback == NULL && in_callback == NULL) ||
1224             (mCallback != NULL && in_callback != NULL)) {
1225         mCallback = in_callback;
1226         pthread_mutex_unlock(&mLock);
1227         return ScopedAStatus::ok();
1228     }
1229 
1230     mCallback = in_callback;
1231     ALOGI("registering callback");
1232 
1233     if (mCallback == NULL) {
1234         if  (!pthread_kill(mPoll, SIGUSR1)) {
1235             pthread_join(mPoll, NULL);
1236             ALOGI("pthread destroyed");
1237         }
1238         pthread_mutex_unlock(&mLock);
1239         return ScopedAStatus::ok();
1240     }
1241 
1242     destroyThread = false;
1243     signal(SIGUSR1, sighandler);
1244 
1245     /*
1246      * Create a background thread if the old callback value is NULL
1247      * and being updated with a new value.
1248      */
1249     if (pthread_create(&mPoll, NULL, work, this)) {
1250         ALOGE("pthread creation failed %d", errno);
1251         mCallback = NULL;
1252     }
1253 
1254     pthread_mutex_unlock(&mLock);
1255     return ScopedAStatus::ok();
1256 }
1257 
handleShellCommand(int in,int out,int err,const char ** argv,uint32_t argc)1258 status_t Usb::handleShellCommand(int in, int out, int err, const char** argv,
1259                                  uint32_t argc) {
1260     uid_t uid = AIBinder_getCallingUid();
1261     if (uid != AID_ROOT && uid != AID_SHELL) {
1262         return ::android::PERMISSION_DENIED;
1263     }
1264 
1265     Vector<String8> utf8Args;
1266     utf8Args.setCapacity(argc);
1267     for (uint32_t i = 0; i < argc; i++) {
1268         utf8Args.push(String8(argv[i]));
1269     }
1270 
1271     if (argc >= 1) {
1272         if (!utf8Args[0].compare(String8("hub-vendor-cmd"))) {
1273             if (utf8Args.size() < 3) {
1274                 dprintf(out, "Incorrect number of argument supplied\n");
1275                 return ::android::UNKNOWN_ERROR;
1276             }
1277             int value, index;
1278             if (!::android::base::ParseInt(utf8Args[1].c_str(), &value) ||
1279                 !::android::base::ParseInt(utf8Args[2].c_str(), &index)) {
1280                 dprintf(out, "Fail to parse arguments\n");
1281                 return ::android::UNKNOWN_ERROR;
1282             }
1283             mUsbHubVendorCmdValue = value;
1284             mUsbHubVendorCmdIndex = index;
1285             ALOGI("USB hub vendor cmd update (wValue 0x%x, wIndex 0x%x)\n",
1286                   mUsbHubVendorCmdValue, mUsbHubVendorCmdIndex);
1287             return ::android::NO_ERROR;
1288         }
1289     }
1290 
1291     dprintf(out, "usage: adb shell cmd hub-vendor-cmd VALUE INDEX\n"
1292                  "  VALUE wValue field in hex format, e.g. 0xf321\n"
1293                  "  INDEX wIndex field in hex format, e.g. 0xf321\n"
1294                  "  The settings take effect next time the hub is enabled\n");
1295 
1296     return ::android::NO_ERROR;
1297 }
1298 
1299 } // namespace usb
1300 } // namespace hardware
1301 } // namespace android
1302 } // aidl
1303