Skip to content

Commit c2b8a7b

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 #4125 - Upgrade ACRA to 2.13 for fixing square/leakcanary#2568
1 parent 42edfff commit c2b8a7b

File tree

7 files changed

+245
-164
lines changed

7 files changed

+245
-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

+61-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,13 +66,13 @@ 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
6872
import java.security.GeneralSecurityException
6973
import java.security.KeyStore
7074
import java.util.LinkedList
75+
import java.util.concurrent.TimeUnit
7176
import javax.net.ssl.KeyManagerFactory
7277
import javax.net.ssl.TrustManagerFactory
7378
import kotlin.concurrent.thread
@@ -79,6 +84,7 @@ import kotlin.concurrent.thread
7984
* Edited by zent-co on 30-07-2019 Edited by bowiechen on 2019-10-19.
8085
*/
8186
class FtpService : Service(), Runnable {
87+
private val serviceScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
8288
private val binder: IBinder = ObtainableServiceBinder(this)
8389

8490
// Service will broadcast via event bus when server start/stop
@@ -95,6 +101,12 @@ class FtpService : Service(), Runnable {
95101
private var isStartedByTile = false
96102
private lateinit var wakeLock: PowerManager.WakeLock
97103

104+
private fun publishEvent(event: FtpReceiverActions) {
105+
serviceScope.launch {
106+
FtpEventBus.emit(event)
107+
}
108+
}
109+
98110
override fun onStartCommand(
99111
intent: Intent?,
100112
flags: Int,
@@ -126,7 +138,7 @@ class FtpService : Service(), Runnable {
126138
} else {
127139
startForeground(NotificationConstants.FTP_ID, notification)
128140
}
129-
return START_NOT_STICKY
141+
return START_STICKY
130142
}
131143

132144
override fun onCreate() {
@@ -143,6 +155,8 @@ class FtpService : Service(), Runnable {
143155

144156
@Suppress("LongMethod")
145157
override fun run() {
158+
// Acquire the WakeLock for 1 hour, per recommended.
159+
wakeLock.acquire(TimeUnit.HOURS.toMillis(1L))
146160
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
147161
FtpServerFactory().run {
148162
val connectionConfigFactory = ConnectionConfigFactory()
@@ -175,7 +189,7 @@ class FtpService : Service(), Runnable {
175189
}.onFailure {
176190
log.warn("failed to decrypt password in ftp service", it)
177191
AppConfig.toast(applicationContext, R.string.error)
178-
preferences.edit().putString(KEY_PREFERENCE_PASSWORD, "").apply()
192+
preferences.edit { putString(KEY_PREFERENCE_PASSWORD, "") }
179193
isPasswordProtected = false
180194
}
181195
}
@@ -224,9 +238,9 @@ class FtpService : Service(), Runnable {
224238
)
225239
fac.isImplicitSsl = true
226240
} catch (e: GeneralSecurityException) {
227-
preferences.edit().putBoolean(KEY_PREFERENCE_SECURE, false).apply()
241+
preferences.edit { putBoolean(KEY_PREFERENCE_SECURE, false) }
228242
} catch (e: IOException) {
229-
preferences.edit().putBoolean(KEY_PREFERENCE_SECURE, false).apply()
243+
preferences.edit { putBoolean(KEY_PREFERENCE_SECURE, false) }
230244
}
231245
}
232246
fac.port = getPort(preferences)
@@ -237,23 +251,22 @@ class FtpService : Service(), Runnable {
237251
server =
238252
createServer().apply {
239253
start()
240-
EventBus.getDefault()
241-
.post(
242-
if (isStartedByTile) {
243-
FtpReceiverActions.STARTED_FROM_TILE
244-
} else {
245-
FtpReceiverActions.STARTED
246-
},
247-
)
254+
publishEvent(
255+
if (isStartedByTile) {
256+
FtpReceiverActions.STARTED_FROM_TILE
257+
} else {
258+
FtpReceiverActions.STARTED
259+
},
260+
)
248261
}
249262
}.onFailure {
250-
EventBus.getDefault().post(FtpReceiverActions.FAILED_TO_START)
263+
wakeLock.release()
264+
publishEvent(FtpReceiverActions.FAILED_TO_START)
251265
}
252266
}
253267
}
254268

255269
override fun onDestroy() {
256-
wakeLock.release()
257270
serverThread?.let { serverThread ->
258271
serverThread.interrupt()
259272
// wait 10 sec for server thread to finish
@@ -263,9 +276,13 @@ class FtpService : Service(), Runnable {
263276
Companion.serverThread = null
264277
}
265278
server?.stop().also {
266-
EventBus.getDefault().post(FtpReceiverActions.STOPPED)
279+
publishEvent(FtpReceiverActions.STOPPED)
267280
}
268281
}
282+
283+
if (wakeLock.isHeld) {
284+
wakeLock.release()
285+
}
269286
}
270287

271288
// Restart the service if the app is closed from the recent list
@@ -312,39 +329,6 @@ class FtpService : Service(), Runnable {
312329
const val TAG_STARTED_BY_TILE = "started_by_tile"
313330
// attribute of action_started, used by notification
314331

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-
348332
/**
349333
* Return a list of available ciphers for ftpserver.
350334
*
@@ -355,7 +339,34 @@ class FtpService : Service(), Runnable {
355339
* @see [javax.net.ssl.SSLEngine]
356340
*/
357341
@JvmStatic
358-
val enabledCipherSuites = _enabledCipherSuites
342+
val enabledCipherSuites: Array<String> =
343+
LinkedList<String>().apply {
344+
if (SDK_INT >= Q) {
345+
add("TLS_AES_128_GCM_SHA256")
346+
add("TLS_AES_256_GCM_SHA384")
347+
add("TLS_CHACHA20_POLY1305_SHA256")
348+
}
349+
if (SDK_INT >= N) {
350+
add("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256")
351+
add("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256")
352+
}
353+
if (SDK_INT >= LOLLIPOP) {
354+
add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA")
355+
add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256")
356+
add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA")
357+
add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384")
358+
add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")
359+
add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
360+
add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA")
361+
add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384")
362+
add("TLS_RSA_WITH_AES_128_GCM_SHA256")
363+
add("TLS_RSA_WITH_AES_256_GCM_SHA384")
364+
}
365+
if (SDK_INT < LOLLIPOP) {
366+
add("TLS_RSA_WITH_AES_128_CBC_SHA")
367+
add("TLS_RSA_WITH_AES_256_CBC_SHA")
368+
}
369+
}.toTypedArray()
359370

360371
private var serverThread: Thread? = null
361372
private var server: FtpServer? = null

0 commit comments

Comments
 (0)