Skip to content

Commit 27cc6da

Browse files
author
Sergey Chelombitko
committed
Clean-up waiting for a device logic
1 parent cadcc6d commit 27cc6da

File tree

5 files changed

+26
-38
lines changed

5 files changed

+26
-38
lines changed

core/src/main/kotlin/com/malinskiy/marathon/device/DeviceProvider.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ package com.malinskiy.marathon.device
33
import kotlinx.coroutines.flow.Flow
44

55
interface DeviceProvider : AutoCloseable {
6-
val deviceInitializationTimeoutMillis: Long
6+
val deviceEvents: Flow<DeviceEvent>
7+
78
suspend fun initialize()
89
suspend fun terminate()
9-
10-
val deviceEvents: Flow<DeviceEvent>
1110
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
package com.malinskiy.marathon.exceptions
22

3-
class NoDevicesException(message: String = "No devices found") : RuntimeException(message)
3+
class NoDevicesException(cause: Throwable) : RuntimeException("No devices found", cause)

core/src/main/kotlin/com/malinskiy/marathon/execution/Scheduler.kt

+4-7
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import kotlinx.coroutines.CoroutineScope
2424
import kotlinx.coroutines.DelicateCoroutinesApi
2525
import kotlinx.coroutines.Job
2626
import kotlinx.coroutines.TimeoutCancellationException
27-
import kotlinx.coroutines.cancelAndJoin
2827
import kotlinx.coroutines.channels.SendChannel
2928
import kotlinx.coroutines.delay
3029
import kotlinx.coroutines.flow.filter
@@ -66,16 +65,14 @@ class Scheduler(
6665
initializeCache(scope)
6766

6867
try {
69-
withTimeout(deviceProvider.deviceInitializationTimeoutMillis) {
68+
withTimeout(configuration.noDevicesTimeoutMillis) {
7069
while (pools.isEmpty()) {
71-
delay(100)
70+
logger.debug("Waiting for a device...")
71+
delay(500L)
7272
}
7373
}
7474
} catch (e: TimeoutCancellationException) {
75-
logger.warn("Timeout waiting for non-empty pools", e)
76-
77-
job.cancelAndJoin()
78-
throw NoDevicesException()
75+
throw NoDevicesException(e)
7976
}
8077
}
8178

vendor/vendor-android/ddmlib/src/main/kotlin/com/malinskiy/marathon/android/ddmlib/DdmlibDeviceProvider.kt

+17-24
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.malinskiy.marathon.android.ddmlib
33
import com.android.ddmlib.AndroidDebugBridge
44
import com.android.ddmlib.DdmPreferences
55
import com.android.ddmlib.IDevice
6-
import com.android.ddmlib.TimeoutException
76
import com.malinskiy.marathon.actor.unboundedChannel
87
import com.malinskiy.marathon.analytics.internal.pub.Track
98
import com.malinskiy.marathon.android.AndroidAppInstaller
@@ -24,12 +23,15 @@ import kotlinx.coroutines.CompletableJob
2423
import kotlinx.coroutines.CoroutineScope
2524
import kotlinx.coroutines.Dispatchers
2625
import kotlinx.coroutines.SupervisorJob
26+
import kotlinx.coroutines.TimeoutCancellationException
2727
import kotlinx.coroutines.cancel
2828
import kotlinx.coroutines.channels.Channel
2929
import kotlinx.coroutines.delay
3030
import kotlinx.coroutines.flow.Flow
3131
import kotlinx.coroutines.flow.consumeAsFlow
32+
import kotlinx.coroutines.isActive
3233
import kotlinx.coroutines.launch
34+
import kotlinx.coroutines.time.withTimeout
3335
import java.time.Duration
3436
import java.util.concurrent.ConcurrentHashMap
3537
import java.util.concurrent.ConcurrentMap
@@ -54,8 +56,6 @@ class DdmlibDeviceProvider(
5456
private val job = SupervisorJob()
5557
private val coroutineScope = CoroutineScope(job + dispatcher)
5658

57-
override val deviceInitializationTimeoutMillis: Long = 180_000
58-
5959
override val deviceEvents: Flow<DeviceEvent>
6060
get() = channel.consumeAsFlow()
6161

@@ -74,31 +74,14 @@ class DdmlibDeviceProvider(
7474
logger.debug("Reusing existing ADB bridge")
7575
}
7676

77-
var getDevicesCountdown = config.noDevicesTimeoutMillis
78-
val sleepTime = DEFAULT_DDM_LIB_SLEEP_TIME
79-
while (!adb.hasInitialDeviceList() || !adb.hasDevices() && getDevicesCountdown >= 0) {
80-
logger.debug("No devices, waiting...")
81-
82-
try {
83-
delay(sleepTime)
84-
} catch (e: InterruptedException) {
85-
throw TimeoutException("Timeout getting device list", e)
86-
}
87-
getDevicesCountdown -= sleepTime
88-
}
89-
90-
logger.debug("Finished waiting for a device")
77+
adb.ensureInitialized()
9178

9279
if (!newAdbCreated && adb.devices.isNotEmpty()) {
9380
logger.debug("Initial connected devices: {}", adb.devices.joinToString(", "))
9481
adb.devices.forEach {
9582
deviceConnected(it)
9683
}
9784
}
98-
99-
if (!adb.hasInitialDeviceList() || !adb.hasDevices()) {
100-
throw NoDevicesException()
101-
}
10285
}
10386

10487
private fun getDeviceOrPut(androidDevice: DdmlibAndroidDevice): DdmlibAndroidDevice {
@@ -122,8 +105,6 @@ class DdmlibDeviceProvider(
122105
}
123106
}
124107

125-
private fun AndroidDebugBridge.hasDevices(): Boolean = devices.isNotEmpty()
126-
127108
override suspend fun terminate() {
128109
job.completeRecursively()
129110
job.join()
@@ -216,6 +197,19 @@ class DdmlibDeviceProvider(
216197
parentJob = job
217198
)
218199

200+
private suspend fun AndroidDebugBridge.ensureInitialized() {
201+
try {
202+
withTimeout(ADB_INIT_TIMEOUT) {
203+
while (isActive && !hasInitialDeviceList()) {
204+
logger.debug("Waiting for ADB initialization...")
205+
delay(500L)
206+
}
207+
}
208+
} catch (e: TimeoutCancellationException) {
209+
throw NoDevicesException(e)
210+
}
211+
}
212+
219213
private val vendorConfiguration: AndroidConfiguration
220214
get() = config.vendorConfiguration as AndroidConfiguration
221215

@@ -229,6 +223,5 @@ class DdmlibDeviceProvider(
229223
companion object {
230224
private val ADB_INIT_TIMEOUT = Duration.ofSeconds(60)
231225
private const val DEFAULT_DDM_LIB_TIMEOUT = 30000
232-
private const val DEFAULT_DDM_LIB_SLEEP_TIME = 500L
233226
}
234227
}

vendor/vendor-test/src/main/kotlin/com/malinskiy/marathon/test/StubDeviceProvider.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ class StubDeviceProvider : DeviceProvider {
1515
private val channel: Channel<DeviceEvent> = unboundedChannel()
1616
var providingLogic: (suspend (Channel<DeviceEvent>) -> Unit)? = null
1717

18-
override val deviceInitializationTimeoutMillis: Long = 180_000
19-
override suspend fun initialize() = Unit
20-
2118
override val deviceEvents: Flow<DeviceEvent>
2219
get() {
2320
providingLogic?.let {
@@ -29,6 +26,8 @@ class StubDeviceProvider : DeviceProvider {
2926
return channel.consumeAsFlow()
3027
}
3128

29+
override suspend fun initialize() = Unit
30+
3231
override suspend fun terminate() {
3332
channel.close()
3433
}

0 commit comments

Comments
 (0)