Skip to content

Commit 1c72f8b

Browse files
committed
#1916 fix refactoring of root checks to not hang the entire app
1 parent 339fe6f commit 1c72f8b

5 files changed

Lines changed: 48 additions & 50 deletions

File tree

base/src/main/java/io/github/sds100/keymapper/base/promode/SystemBridgeAutoStarter.kt

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import kotlinx.coroutines.flow.flowOf
4646
import kotlinx.coroutines.flow.map
4747
import kotlinx.coroutines.launch
4848
import kotlinx.coroutines.withTimeout
49+
import kotlinx.coroutines.withTimeoutOrNull
4950
import timber.log.Timber
5051

5152
/**
@@ -78,45 +79,47 @@ class SystemBridgeAutoStarter @Inject constructor(
7879
@SuppressLint("NewApi")
7980
@OptIn(ExperimentalCoroutinesApi::class)
8081
private val autoStartTypeFlow: Flow<AutoStartType?> =
81-
suAdapter.isRootGranted.flatMapLatest { isRooted ->
82-
if (isRooted) {
83-
flowOf(AutoStartType.ROOT)
84-
} else {
85-
val useShizukuFlow =
86-
combine(
87-
shizukuAdapter.isStarted,
88-
permissionAdapter.isGrantedFlow(Permission.SHIZUKU),
89-
) { isStarted, isGranted ->
90-
isStarted && isGranted
91-
}
92-
93-
useShizukuFlow.flatMapLatest { useShizuku ->
94-
if (useShizuku) {
95-
flowOf(AutoStartType.SHIZUKU)
96-
} else if (buildConfig.sdkInt >= Build.VERSION_CODES.R) {
97-
val isAdbAutoStartAllowed = combine(
98-
permissionAdapter.isGrantedFlow(Permission.WRITE_SECURE_SETTINGS),
99-
networkAdapter.isWifiConnected,
100-
) { isWriteSecureSettingsGranted, isWifiConnected ->
101-
isWriteSecureSettingsGranted &&
102-
isWifiConnected &&
103-
setupController.isAdbPaired()
82+
suAdapter.isRootGranted
83+
.filterNotNull()
84+
.flatMapLatest { isRooted ->
85+
if (isRooted) {
86+
flowOf(AutoStartType.ROOT)
87+
} else {
88+
val useShizukuFlow =
89+
combine(
90+
shizukuAdapter.isStarted,
91+
permissionAdapter.isGrantedFlow(Permission.SHIZUKU),
92+
) { isStarted, isGranted ->
93+
isStarted && isGranted
10494
}
10595

106-
isAdbAutoStartAllowed.distinctUntilChanged()
107-
.map { isAdbAutoStartAllowed ->
108-
if (isAdbAutoStartAllowed) {
109-
AutoStartType.ADB
110-
} else {
111-
null
112-
}
113-
}.filterNotNull()
114-
} else {
115-
flowOf(null)
96+
useShizukuFlow.flatMapLatest { useShizuku ->
97+
if (useShizuku) {
98+
flowOf(AutoStartType.SHIZUKU)
99+
} else if (buildConfig.sdkInt >= Build.VERSION_CODES.R) {
100+
val isAdbAutoStartAllowed = combine(
101+
permissionAdapter.isGrantedFlow(Permission.WRITE_SECURE_SETTINGS),
102+
networkAdapter.isWifiConnected,
103+
) { isWriteSecureSettingsGranted, isWifiConnected ->
104+
isWriteSecureSettingsGranted &&
105+
isWifiConnected &&
106+
setupController.isAdbPaired()
107+
}
108+
109+
isAdbAutoStartAllowed.distinctUntilChanged()
110+
.map { isAdbAutoStartAllowed ->
111+
if (isAdbAutoStartAllowed) {
112+
AutoStartType.ADB
113+
} else {
114+
null
115+
}
116+
}.filterNotNull()
117+
} else {
118+
flowOf(null)
119+
}
116120
}
117121
}
118122
}
119-
}
120123

121124
/**
122125
* This emits values when the system bridge needs restarting after it being killed.
@@ -187,7 +190,11 @@ class SystemBridgeAutoStarter @Inject constructor(
187190
@Suppress("DEPRECATION")
188191
val upgradedFromPreVersion4 = preferences.get(Keys.hasRootPermissionLegacy).first() != null
189192

190-
if (upgradedFromPreVersion4 && suAdapter.isRootGranted.first()) {
193+
val isRooted: Boolean = withTimeoutOrNull(1000) {
194+
suAdapter.isRootGranted.filterNotNull().first()
195+
} ?: false
196+
197+
if (upgradedFromPreVersion4 && isRooted) {
191198
Timber.i(
192199
"Auto starting system bridge because upgraded from pre version 4.0 and was rooted",
193200
)

base/src/main/java/io/github/sds100/keymapper/base/promode/SystemBridgeSetupUseCase.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class SystemBridgeSetupUseCaseImpl @Inject constructor(
120120
}
121121
}
122122

123-
override val isRootGranted: Flow<Boolean> = suAdapter.isRootGranted
123+
override val isRootGranted: Flow<Boolean> = suAdapter.isRootGranted.map { it ?: false }
124124

125125
override val shizukuSetupState: Flow<ShizukuSetupState> = combine(
126126
shizukuAdapter.isInstalled,

base/src/main/java/io/github/sds100/keymapper/base/settings/ConfigSettingsUseCase.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class ConfigSettingsUseCaseImpl @Inject constructor(
5757
Theme.entries.single { it.value == value.toInt() }
5858
}
5959

60-
override val isRootGranted: Flow<Boolean> = suAdapter.isRootGranted
60+
override val isRootGranted: Flow<Boolean> = suAdapter.isRootGranted.map { it ?: false }
6161

6262
override val isWriteSecureSettingsGranted: Flow<Boolean> = channelFlow {
6363
send(permissionAdapter.isGranted(Permission.WRITE_SECURE_SETTINGS))

system/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ class AndroidPermissionAdapter @Inject constructor(
278278
Manifest.permission.SEND_SMS,
279279
) == PERMISSION_GRANTED
280280

281-
Permission.ROOT -> suAdapter.isRootGranted.firstBlocking()
281+
Permission.ROOT -> suAdapter.isRootGranted.firstBlocking() ?: false
282282

283283
Permission.IGNORE_BATTERY_OPTIMISATION ->
284284
powerManager?.isIgnoringBatteryOptimizations(buildConfigProvider.packageName) ?: false

system/src/main/java/io/github/sds100/keymapper/system/root/SuAdapter.kt

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import kotlinx.coroutines.Dispatchers
1010
import kotlinx.coroutines.Job
1111
import kotlinx.coroutines.flow.Flow
1212
import kotlinx.coroutines.flow.MutableStateFlow
13-
import kotlinx.coroutines.flow.filterNotNull
1413
import kotlinx.coroutines.flow.update
1514
import kotlinx.coroutines.launch
1615
import kotlinx.coroutines.withContext
@@ -20,15 +19,7 @@ import timber.log.Timber
2019
class SuAdapterImpl @Inject constructor(private val coroutineScope: CoroutineScope) :
2120
BaseShellAdapter(),
2221
SuAdapter {
23-
/**
24-
* This is initially null while it waits for the invalidateJob to complete asynchronously.
25-
*/
26-
private val _isRootGranted: MutableStateFlow<Boolean?> = MutableStateFlow(null)
27-
28-
/**
29-
* This flow will block until the invalidateJob is finished.
30-
*/
31-
override val isRootGranted: Flow<Boolean> = _isRootGranted.filterNotNull()
22+
override val isRootGranted: MutableStateFlow<Boolean?> = MutableStateFlow(null)
3223

3324
private var invalidateJob: Job? = null
3425

@@ -55,7 +46,7 @@ class SuAdapterImpl @Inject constructor(private val coroutineScope: CoroutineSco
5546
try {
5647
// Close the shell so a new one is started without root permission.
5748
val isRooted = getIsRooted()
58-
_isRootGranted.update { isRooted }
49+
isRootGranted.update { isRooted }
5950
} catch (e: Exception) {
6051
Timber.e("Exception invalidating root detection: $e")
6152
}
@@ -71,7 +62,7 @@ class SuAdapterImpl @Inject constructor(private val coroutineScope: CoroutineSco
7162
}
7263

7364
interface SuAdapter : ShellAdapter {
74-
val isRootGranted: Flow<Boolean>
65+
val isRootGranted: Flow<Boolean?>
7566

7667
fun requestPermission()
7768
}

0 commit comments

Comments
 (0)