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, ¤tPortStatus);
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, ¤tPortStatus);
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, ¤tPortStatus);
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, ¤tPortStatus);
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, ¤tRole) == 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, ¤tRole) == 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, ¤tRole) == 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, ¤tPortStatus);
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, ¤tPortStatus);
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, ¤tPortStatus);
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