USB: HAL: Rework USB audio reset recovery implementation

Android CTS/VTS tests verifies USB DEVFS functionality, which allows for
userspace entities to override the currently binded class driver.  The
existing mechanism monitors USB interface unbind events to determine if an
USB bus reset occurs.  However, the USB DEVFS unbind and USB bus reset
results in the same operations.  This leads to the USB DEVFS unbind ioctl
to kick in the recovery mechanism.

Due to this, the Android CTS/VTS test case fails.  Modify the current
implementation to monitor for USB interface change uevents, which is going
to be generated from newly added pre/post reset callbacks within the DWC3
MSM driver.

Change-Id: I5677c08aefc012dce21d07b04817b7736d2abafb
diff --git a/hal/Usb.cpp b/hal/Usb.cpp
index 0310d0a..418f43c 100644
--- a/hal/Usb.cpp
+++ b/hal/Usb.cpp
@@ -15,6 +15,10 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
+ * Changes from Qualcomm Innovation Center are provided under the following license:
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause-Clear
  */
 
 #define LOG_TAG "android.hardware.usb@1.2-service-qti"
@@ -54,20 +58,14 @@
 
 // Set by the signal handler to destroy the thread
 volatile bool destroyThread;
-
-volatile bool armResetRecovery = false;
-std::string audioDev = "";
-volatile int monDisconnect = 0;
-pthread_t mDisMon;
+// USB bus reset recovery active
+int usbResetRecov;
 
 static void checkUsbWakeupSupport(struct Usb *usb);
 static void checkUsbInHostMode(struct Usb *usb);
 static void checkUsbDeviceAutoSuspend(const std::string& devicePath);
 static bool checkUsbInterfaceAutoSuspend(const std::string& devicePath,
         const std::string &intf);
-static bool isAudioClass(const std::string& devicePath,
-        const std::string &intf);
-static bool isRootHub(const std::string& devicePath);
 
 static int32_t readFile(const std::string &filename, std::string *contents) {
   FILE *fp;
@@ -736,27 +734,9 @@
   }
 }
 
-// USB audio device disconnect monitor
-void *disconnectMon(void *param) {
-  std::string *devicePath = (std::string *)param;
-  int timeout = 300;
-
-  while (!destroyThread && monDisconnect) {
-    if (!timeout) {
-	  ALOGI("disconnectMon timed out, deauthorizing");
-	  writeFile(*devicePath + "/../authorized", "0");
-	  break;
-	}
-	timeout--;
-	usleep(1000);
-  }
-
-  return NULL;
-}
-
 static void uevent_event(uint32_t /*epevents*/, struct data *payload) {
   char msg[UEVENT_MSG_LEN + 2];
-  int n;
+  int n, ret;
   std::string gadgetName = GetProperty(USB_CONTROLLER_PROP, "");
   static std::regex add_regex("add@(/devices/platform/soc/.*dwc3/xhci-hcd\\.\\d\\.auto/"
                               "usb\\d/\\d-\\d(?:/[\\d\\.-]+)*)");
@@ -764,7 +744,7 @@
                               "usb\\d)/\\d-\\d(?:/[\\d\\.-]+)*)");
   static std::regex bind_regex("bind@(/devices/platform/soc/.*dwc3/xhci-hcd\\.\\d\\.auto/"
                                "usb\\d/\\d-\\d(?:/[\\d\\.-]+)*)/([^/]*:[^/]*)");
-  static std::regex unbind_regex("unbind@(/devices/platform/soc/.*dwc3/xhci-hcd\\.\\d\\.auto/"
+  static std::regex bus_reset_regex("change@(/devices/platform/soc/.*dwc3/xhci-hcd\\.\\d\\.auto/"
                                "usb\\d/\\d-\\d(?:/[\\d\\.-]+)*)/([^/]*:[^/]*)");
   static std::regex udc_regex("(add|remove)@/devices/platform/soc/.*/" + gadgetName +
                               "/udc/" + gadgetName);
@@ -788,23 +768,36 @@
       std::csub_match submatch = match[1];
       checkUsbDeviceAutoSuspend("/sys" +  submatch.str());
     }
-  } else if (std::regex_match(msg, match, bind_regex)) {
+  } else if (!payload->usb->mIgnoreWakeup && std::regex_match(msg, match, bind_regex)) {
+    if (match.size() == 3) {
+      std::csub_match devpath = match[1];
+      std::csub_match intfpath = match[2];
+      checkUsbInterfaceAutoSuspend("/sys" + devpath.str(), intfpath.str());
+    }
+  } else if (std::regex_match(msg, match, bus_reset_regex)) {
     std::csub_match devpath = match[1];
     std::csub_match intfpath = match[2];
-    std::string dpath;
 
-    if (!payload->usb->mIgnoreWakeup) {
-        if (match.size() == 3) {
-          checkUsbInterfaceAutoSuspend("/sys" + devpath.str(), intfpath.str());
-        }
-    }
+    ALOGI("Handling USB bus reset recovery");
 
-    dpath.assign("/sys" + devpath.str());
-    // Limit the audio path recovery to devices directly connected to the root hub.
-    // Save the device path to the audio device, which will trigger the recovery.
-    if (audioDev == "" && isAudioClass(dpath, intfpath.str()) && isRootHub(dpath)) {
-       audioDev.assign(dpath);
-       armResetRecovery = true;
+    // Limit the recovery to when an audio device is connected directly to
+    // the roothub.  A path reference is needed so other non-audio class
+    // related devices don't trigger the disconnectMon. (unbind uevent occurs
+    // after sysfs files are cleaned, can't check bInterfaceClass)
+    usbResetRecov = 1;
+    ret = writeFile("/sys" + devpath.str() + "/../authorized", "0");
+    if (ret < 0)
+      ALOGI("unable to deauthorize device");
+  } else if (std::regex_match(msg, match, remove_regex)) {
+    std::csub_match devpath = match[1];
+    std::csub_match parentpath = match[2];
+
+    ALOGI("Disconnect received");
+    if (usbResetRecov) {
+      usbResetRecov = 0;
+      //Allow interfaces to disconnect
+      std::this_thread::sleep_for(std::chrono::milliseconds(100));
+      writeFile("/sys" + parentpath.str() + "/authorized", "1");
     }
   } else if (std::regex_match(msg, match, udc_regex)) {
     if (!strncmp(msg, "add", 3)) {
@@ -817,6 +810,7 @@
         ALOGI("Binding UDC %s to ConfigFS", gadgetName.c_str());
         writeFile("/config/usb_gadget/g1/UDC", gadgetName);
       }
+
     } else {
       // When the UDC is removed, the ConfigFS gadget will no longer be
       // bound. If ADBD is running it would keep opening/writing to its
@@ -826,40 +820,6 @@
       // Setting this property stops ADBD from proceeding with the retry.
       SetProperty(VENDOR_USB_ADB_DISABLED_PROP, "1");
     }
-  } else if (std::regex_match(msg, match, unbind_regex)) {
-    std::csub_match devpath = match[1];
-    std::csub_match intfpath = match[2];
-    std::string dpath;
-
-    dpath.assign("/sys" + devpath.str());
-    // Limit the recovery to when an audio device is connected directly to
-    // the roothub.  A path reference is needed so other non-audio class
-    // related devices don't trigger the disconnectMon. (unbind uevent occurs
-    // after sysfs files are cleaned, can't check bInterfaceClass)
-    if (armResetRecovery && audioDev == dpath) {
-        monDisconnect = 1;
-        armResetRecovery = false;
-        if (pthread_create(&mDisMon, NULL, disconnectMon, &audioDev)) {
-            ALOGE("pthread creation failed %d", errno);
-        }
-    }
-  } else if (std::regex_match(msg, match, remove_regex)) {
-    std::csub_match devpath = match[1];
-    std::csub_match parentpath = match[2];
-    std::string dpath;
-
-    dpath.assign("/sys" + devpath.str());
-    ALOGI("Disconnect received");
-    if (monDisconnect) {
-      monDisconnect = 0;
-      if (!pthread_kill(mDisMon, 0)) {
-        pthread_join(mDisMon, NULL);
-      }
-      writeFile("/sys" + parentpath.str() + "/authorized", "1");
-    }
-    if (audioDev == dpath)
-      audioDev = "";
-    armResetRecovery = false;
   }
 }
 
@@ -1098,27 +1058,6 @@
   }
 }
 
-static bool isRootHub(const std::string& devicePath) {
-  std::string devpath;
-  int path;
-
-  readFile(devicePath + "/../devpath", &devpath);
-  path = std::stoi(devpath, 0, 16);
-
-  return !path;
-}
-
-static bool isAudioClass(const std::string& devicePath,
-        const std::string &intf) {
-  std::string bInterfaceClass;
-  int interfaceClass, ret = -1;
-
-  readFile(devicePath + "/" + intf + "/bInterfaceClass", &bInterfaceClass);
-  interfaceClass = std::stoi(bInterfaceClass, 0, 16);
-
-  return (interfaceClass == USB_CLASS_AUDIO);
-}
-
 /*
  * allow specific USB device idProduct and idVendor to auto suspend
  */