From 32bfb874e32991685150ad7b9e8785b2b0ec9a7e Mon Sep 17 00:00:00 2001 From: Phil Burk Date: Fri, 30 Oct 2015 14:26:34 -0700 Subject: [PATCH] UsbMidiDeviceJNI: fix race condition Try multiple times to open the MIDI control device. This fixes a race condition that caused Android to sometimes not see a USB MIDI keyboard when it was plugged in. Bug: 25328161 Change-Id: Ic72c5859364fc56bf7a40c1b1c9791c42827ea63 Signed-off-by: Phil Burk --- .../jni/com_android_server_UsbMidiDevice.cpp | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/services/core/jni/com_android_server_UsbMidiDevice.cpp b/services/core/jni/com_android_server_UsbMidiDevice.cpp index 06b9bc3c01ec8..e12a01661a440 100644 --- a/services/core/jni/com_android_server_UsbMidiDevice.cpp +++ b/services/core/jni/com_android_server_UsbMidiDevice.cpp @@ -43,12 +43,26 @@ android_server_UsbMidiDevice_get_subdevice_count(JNIEnv *env, jobject /* thiz */ jint card, jint device) { char path[100]; + int fd; + const int kMaxRetries = 10; + const int kSleepMicroseconds = 2000; snprintf(path, sizeof(path), "/dev/snd/controlC%d", card); - int fd = open(path, O_RDWR); - if (fd < 0) { - ALOGE("could not open %s", path); - return 0; + // This control device may not have been created yet. So we should + // try to open it several times to prevent intermittent failure + // from a race condition. + int retryCounter = 0; + while ((fd = open(path, O_RDWR)) < 0) { + if (++retryCounter > kMaxRetries) { + ALOGE("timed out after %d tries, could not open %s", retryCounter, path); + return 0; + } else { + ALOGW("attempt #%d, could not open %s", retryCounter, path); + // Increase the sleep interval each time. + // 10 retries will total 2 * sum(1..10) = 110 milliseconds. + // Typically the device should be ready in 5-10 milliseconds. + usleep(kSleepMicroseconds * retryCounter); + } } struct snd_rawmidi_info info;