Skip to content

Commit 5abbb83

Browse files
committed
FTP server minor improvements
- Replace EventBus with kotlinx.coroutines - FtpServerFragment update code to recommended - FtpService explicitly acquires wakelock and enforces START_STICKY to ensure it's still running in the background even in the doze mode. Fixes TeamAmaze#4125 - Upgrade ACRA to 2.13 for fixing square/leakcanary#2568
1 parent 42edfff commit 5abbb83

File tree

7 files changed

+242
-164
lines changed

7 files changed

+242
-164
lines changed

app/build.gradle

-2
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,6 @@ dependencies {
196196
implementation libs.apache.ftpserver.ftplet.api
197197
implementation libs.apache.ftpserver.core
198198

199-
implementation libs.eventbus
200-
201199
implementation libs.libsu.core
202200
implementation libs.libsu.io
203201

app/src/main/AndroidManifest.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,8 @@
286286
android:exported="true"
287287
android:icon="@drawable/ic_ftp_dark"
288288
android:label="@string/ftp"
289-
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
289+
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
290+
tools:targetApi="24">
290291
<intent-filter>
291292
<action
292293
android:name="android.service.quicksettings.action.QS_TILE" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.amaze.filemanager.asynchronous.services.ftp
2+
3+
import com.amaze.filemanager.ui.fragments.FtpServerFragment
4+
import kotlinx.coroutines.flow.MutableSharedFlow
5+
import kotlinx.coroutines.flow.asSharedFlow
6+
7+
/**
8+
* Replacement event bus to handle [FtpService] events using Kotlin's Flow.
9+
*
10+
* Original idea: https://mirchev.medium.com/its-21st-century-stop-using-eventbus-3ff5d9c6a00f
11+
*
12+
* @see [FtpService]
13+
* @see [FtpTileService]
14+
* @see [FtpServerFragment]
15+
*/
16+
object FtpEventBus {
17+
private val _events = MutableSharedFlow<FtpService.FtpReceiverActions>(replay = 0)
18+
val events = _events.asSharedFlow()
19+
20+
/**
21+
* Emit the event signal to the event bus as [MutableSharedFlow].
22+
*
23+
* @param event The event to be emitted.
24+
*/
25+
suspend fun emit(event: FtpService.FtpReceiverActions) {
26+
_events.emit(event)
27+
}
28+
}

app/src/main/java/com/amaze/filemanager/asynchronous/services/ftp/FtpService.kt

+59-50
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import android.os.PowerManager
4040
import android.os.SystemClock
4141
import android.provider.DocumentsContract
4242
import androidx.core.app.ServiceCompat
43+
import androidx.core.content.edit
4344
import androidx.preference.PreferenceManager
4445
import com.amaze.filemanager.BuildConfig
4546
import com.amaze.filemanager.R
@@ -52,6 +53,10 @@ import com.amaze.filemanager.ui.notifications.FtpNotification
5253
import com.amaze.filemanager.ui.notifications.NotificationConstants
5354
import com.amaze.filemanager.utils.ObtainableServiceBinder
5455
import com.amaze.filemanager.utils.PasswordUtil
56+
import kotlinx.coroutines.CoroutineScope
57+
import kotlinx.coroutines.Dispatchers
58+
import kotlinx.coroutines.SupervisorJob
59+
import kotlinx.coroutines.launch
5560
import org.apache.ftpserver.ConnectionConfigFactory
5661
import org.apache.ftpserver.FtpServer
5762
import org.apache.ftpserver.FtpServerFactory
@@ -61,7 +66,6 @@ import org.apache.ftpserver.ssl.ClientAuth
6166
import org.apache.ftpserver.ssl.impl.DefaultSslConfiguration
6267
import org.apache.ftpserver.usermanager.impl.BaseUser
6368
import org.apache.ftpserver.usermanager.impl.WritePermission
64-
import org.greenrobot.eventbus.EventBus
6569
import org.slf4j.Logger
6670
import org.slf4j.LoggerFactory
6771
import java.io.IOException
@@ -79,6 +83,7 @@ import kotlin.concurrent.thread
7983
* Edited by zent-co on 30-07-2019 Edited by bowiechen on 2019-10-19.
8084
*/
8185
class FtpService : Service(), Runnable {
86+
private val serviceScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
8287
private val binder: IBinder = ObtainableServiceBinder(this)
8388

8489
// Service will broadcast via event bus when server start/stop
@@ -95,6 +100,12 @@ class FtpService : Service(), Runnable {
95100
private var isStartedByTile = false
96101
private lateinit var wakeLock: PowerManager.WakeLock
97102

103+
private fun publishEvent(event: FtpReceiverActions) {
104+
serviceScope.launch {
105+
FtpEventBus.emit(event)
106+
}
107+
}
108+
98109
override fun onStartCommand(
99110
intent: Intent?,
100111
flags: Int,
@@ -126,7 +137,7 @@ class FtpService : Service(), Runnable {
126137
} else {
127138
startForeground(NotificationConstants.FTP_ID, notification)
128139
}
129-
return START_NOT_STICKY
140+
return START_STICKY
130141
}
131142

132143
override fun onCreate() {
@@ -143,6 +154,7 @@ class FtpService : Service(), Runnable {
143154

144155
@Suppress("LongMethod")
145156
override fun run() {
157+
wakeLock.acquire()
146158
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
147159
FtpServerFactory().run {
148160
val connectionConfigFactory = ConnectionConfigFactory()
@@ -175,7 +187,7 @@ class FtpService : Service(), Runnable {
175187
}.onFailure {
176188
log.warn("failed to decrypt password in ftp service", it)
177189
AppConfig.toast(applicationContext, R.string.error)
178-
preferences.edit().putString(KEY_PREFERENCE_PASSWORD, "").apply()
190+
preferences.edit { putString(KEY_PREFERENCE_PASSWORD, "") }
179191
isPasswordProtected = false
180192
}
181193
}
@@ -224,9 +236,9 @@ class FtpService : Service(), Runnable {
224236
)
225237
fac.isImplicitSsl = true
226238
} catch (e: GeneralSecurityException) {
227-
preferences.edit().putBoolean(KEY_PREFERENCE_SECURE, false).apply()
239+
preferences.edit { putBoolean(KEY_PREFERENCE_SECURE, false) }
228240
} catch (e: IOException) {
229-
preferences.edit().putBoolean(KEY_PREFERENCE_SECURE, false).apply()
241+
preferences.edit { putBoolean(KEY_PREFERENCE_SECURE, false) }
230242
}
231243
}
232244
fac.port = getPort(preferences)
@@ -237,23 +249,22 @@ class FtpService : Service(), Runnable {
237249
server =
238250
createServer().apply {
239251
start()
240-
EventBus.getDefault()
241-
.post(
242-
if (isStartedByTile) {
243-
FtpReceiverActions.STARTED_FROM_TILE
244-
} else {
245-
FtpReceiverActions.STARTED
246-
},
247-
)
252+
publishEvent(
253+
if (isStartedByTile) {
254+
FtpReceiverActions.STARTED_FROM_TILE
255+
} else {
256+
FtpReceiverActions.STARTED
257+
},
258+
)
248259
}
249260
}.onFailure {
250-
EventBus.getDefault().post(FtpReceiverActions.FAILED_TO_START)
261+
wakeLock.release()
262+
publishEvent(FtpReceiverActions.FAILED_TO_START)
251263
}
252264
}
253265
}
254266

255267
override fun onDestroy() {
256-
wakeLock.release()
257268
serverThread?.let { serverThread ->
258269
serverThread.interrupt()
259270
// wait 10 sec for server thread to finish
@@ -263,9 +274,13 @@ class FtpService : Service(), Runnable {
263274
Companion.serverThread = null
264275
}
265276
server?.stop().also {
266-
EventBus.getDefault().post(FtpReceiverActions.STOPPED)
277+
publishEvent(FtpReceiverActions.STOPPED)
267278
}
268279
}
280+
281+
if (wakeLock.isHeld) {
282+
wakeLock.release()
283+
}
269284
}
270285

271286
// Restart the service if the app is closed from the recent list
@@ -312,39 +327,6 @@ class FtpService : Service(), Runnable {
312327
const val TAG_STARTED_BY_TILE = "started_by_tile"
313328
// attribute of action_started, used by notification
314329

315-
private lateinit var _enabledCipherSuites: Array<String>
316-
317-
init {
318-
_enabledCipherSuites =
319-
LinkedList<String>().apply {
320-
if (SDK_INT >= Q) {
321-
add("TLS_AES_128_GCM_SHA256")
322-
add("TLS_AES_256_GCM_SHA384")
323-
add("TLS_CHACHA20_POLY1305_SHA256")
324-
}
325-
if (SDK_INT >= N) {
326-
add("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
327-
add("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256")
328-
}
329-
if (SDK_INT >= LOLLIPOP) {
330-
add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA")
331-
add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256")
332-
add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA")
333-
add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384")
334-
add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")
335-
add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
336-
add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA")
337-
add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384")
338-
add("TLS_RSA_WITH_AES_128_GCM_SHA256")
339-
add("TLS_RSA_WITH_AES_256_GCM_SHA384")
340-
}
341-
if (SDK_INT < LOLLIPOP) {
342-
add("TLS_RSA_WITH_AES_128_CBC_SHA")
343-
add("TLS_RSA_WITH_AES_256_CBC_SHA")
344-
}
345-
}.toTypedArray()
346-
}
347-
348330
/**
349331
* Return a list of available ciphers for ftpserver.
350332
*
@@ -355,7 +337,34 @@ class FtpService : Service(), Runnable {
355337
* @see [javax.net.ssl.SSLEngine]
356338
*/
357339
@JvmStatic
358-
val enabledCipherSuites = _enabledCipherSuites
340+
val enabledCipherSuites: Array<String> =
341+
LinkedList<String>().apply {
342+
if (SDK_INT >= Q) {
343+
add("TLS_AES_128_GCM_SHA256")
344+
add("TLS_AES_256_GCM_SHA384")
345+
add("TLS_CHACHA20_POLY1305_SHA256")
346+
}
347+
if (SDK_INT >= N) {
348+
add("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
349+
add("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256")
350+
}
351+
if (SDK_INT >= LOLLIPOP) {
352+
add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA")
353+
add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256")
354+
add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA")
355+
add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384")
356+
add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")
357+
add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
358+
add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA")
359+
add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384")
360+
add("TLS_RSA_WITH_AES_128_GCM_SHA256")
361+
add("TLS_RSA_WITH_AES_256_GCM_SHA384")
362+
}
363+
if (SDK_INT < LOLLIPOP) {
364+
add("TLS_RSA_WITH_AES_128_CBC_SHA")
365+
add("TLS_RSA_WITH_AES_256_CBC_SHA")
366+
}
367+
}.toTypedArray()
359368

360369
private var serverThread: Thread? = null
361370
private var server: FtpServer? = null

0 commit comments

Comments
 (0)