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