Use Single Periodic worker to restart

This commit is contained in:
sim 2022-02-22 22:34:10 +01:00
parent 062706f3ae
commit 68dc14a95a
7 changed files with 115 additions and 73 deletions

View File

@ -80,4 +80,5 @@ dependencies {
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("io.reactivex.rxjava2:rxjava:2.2.21")
implementation("com.google.code.gson:gson:2.9.0")
implementation("androidx.work:work-runtime-ktx:2.6.0")
}

View File

@ -86,7 +86,7 @@ class MainActivity : AppCompatActivity() {
format(getString(R.string.main_account_desc), ssoAccount.name)
showLogout = true
invalidateOptionsMenu()
startListener(this)
RestartWorker.start(this)
}
private fun showStart() {
@ -130,15 +130,14 @@ class MainActivity : AppCompatActivity() {
Log.d(TAG, "Restarting the Listener")
val receiver = object : BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
startListener(this@MainActivity)
RestartWorker.start(this@MainActivity, delay = 0)
}
}
val intentFilter = IntentFilter(SERVICE_STOPPED_ACTION)
val intentFilter = IntentFilter(StartService.SERVICE_STOPPED_ACTION)
registerReceiver(receiver, intentFilter)
isServiceStarted = false
StartService.isServiceStarted = false
val serviceIntent = Intent(this, StartService::class.java)
this.stopService(serviceIntent)
startListener(this)
}
private fun logout() {

View File

@ -3,6 +3,7 @@ package org.unifiedpush.distributor.nextpush.receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.PowerManager
import android.util.Log
import org.unifiedpush.distributor.nextpush.account.AccountUtils.isConnected
import org.unifiedpush.distributor.nextpush.api.ApiUtils.apiCreateApp
@ -19,7 +20,6 @@ import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.getDb
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendEndpoint
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendRegistrationFailed
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendUnregistered
import org.unifiedpush.distributor.nextpush.services.wakeLock
import java.lang.Exception
/**
@ -30,8 +30,16 @@ private const val TAG = "RegisterBroadcastReceiver"
class RegisterBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
wakeLock?.acquire(10000L /*10 secs*/)
companion object {
private const val WAKE_LOCK_TAG = "NextPush:RegisterBroadcastReceiver:lock"
private var wakeLock : PowerManager.WakeLock? = null
}
override fun onReceive(context: Context, intent: Intent?) {
wakeLock = (context.getSystemService(Context.POWER_SERVICE) as PowerManager).run {
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG)
}
wakeLock?.acquire(30000L /*30 secs*/)
when (intent!!.action) {
ACTION_REGISTER ->{
Log.i(TAG,"REGISTER")

View File

@ -3,20 +3,13 @@ package org.unifiedpush.distributor.nextpush.receivers
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import org.unifiedpush.distributor.nextpush.services.StartService
import org.unifiedpush.distributor.nextpush.services.RestartWorker
class StartReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
Intent(context, StartService::class.java).also {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(it)
return
}
context.startService(it)
}
RestartWorker.start(context)
}
}
}

View File

@ -0,0 +1,40 @@
package org.unifiedpush.distributor.nextpush.services
import android.content.Context
import android.util.Log
import androidx.work.*
import org.unifiedpush.distributor.nextpush.services.SSEListener.Companion.lastEventDate
import java.util.*
import java.util.concurrent.TimeUnit
private const val UNIQUE_WORK_TAG = "nextpush::RestartWorker::unique"
class RestartWorker (ctx: Context, params: WorkerParameters) : Worker(ctx, params) {
companion object {
private const val TAG = "RestartWorker"
fun start(context: Context, delay: Long? = null) {
val work = PeriodicWorkRequestBuilder<RestartWorker>(20, TimeUnit.MINUTES)
if (delay != null) {
lastEventDate = null
work.setInitialDelay(delay, TimeUnit.SECONDS)
}
val workManager = WorkManager.getInstance(context)
workManager.enqueueUniquePeriodicWork(
UNIQUE_WORK_TAG,
ExistingPeriodicWorkPolicy.REPLACE,
work.build()
)
}
}
override fun doWork(): Result {
Log.d(TAG, "Working")
val currentDate = Calendar.getInstance()
val restartDate = lastEventDate?.add(Calendar.MINUTE, 15)
if (restartDate == null || currentDate.after(restartDate)) {
StartService.startListener(applicationContext)
}
return Result.success()
}
}

View File

@ -1,8 +1,6 @@
package org.unifiedpush.distributor.nextpush.services
import android.content.Context
import android.os.CountDownTimer
import android.os.Looper
import android.util.Base64
import okhttp3.sse.EventSourceListener
import okhttp3.sse.EventSource
@ -16,15 +14,20 @@ import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendMes
import org.unifiedpush.distributor.nextpush.distributor.DistributorUtils.sendUnregistered
import org.unifiedpush.distributor.nextpush.services.NotificationUtils.createWarningNotification
import org.unifiedpush.distributor.nextpush.services.NotificationUtils.deleteWarningNotification
import java.util.*
private const val TAG = "SSEListener"
class SSEListener (val context: Context) : EventSourceListener() {
companion object {
var lastEventDate : Calendar? = null
}
override fun onOpen(eventSource: EventSource, response: Response) {
deleteWarningNotification(context)
nFails = 0
wakeLock?.let {
StartService.nFails = 0
StartService.wakeLock?.let {
while (it.isHeld) {
it.release()
}
@ -38,7 +41,9 @@ class SSEListener (val context: Context) : EventSourceListener() {
override fun onEvent(eventSource: EventSource, id: String?, type: String?, data: String) {
Log.d(TAG, "New SSE message event=$type message=$data")
wakeLock?.acquire(10000L /*10 secs*/)
StartService.wakeLock?.acquire(10000L /*10 secs*/)
lastEventDate = Calendar.getInstance()
when (type) {
"warning" -> Log.d(TAG, "Warning event received.")
"ping" -> Log.d(TAG, "SSE ping received.")
@ -61,7 +66,7 @@ class SSEListener (val context: Context) : EventSourceListener() {
db.unregisterApp(connectorToken)
}
}
wakeLock?.let {
StartService.wakeLock?.let {
if (it.isHeld) {
it.release()
}
@ -69,49 +74,36 @@ class SSEListener (val context: Context) : EventSourceListener() {
}
override fun onClosed(eventSource: EventSource) {
if (!isServiceStarted)
if (!StartService.isServiceStarted)
return
Log.d(TAG, "onClosed: $eventSource")
nFails += 1
StartService.nFails += 1
createWarningNotification(context)
startListener(context)
RestartWorker.start(context, delay = 0)
}
override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) {
if (!isServiceStarted)
if (!StartService.isServiceStarted)
return
Log.d(TAG, "onFailure")
nFails += 1
if (nFails > 1)
createWarningNotification(context)
val timeStop = when (nFails) {
1 -> 2000 // 2sec
2 -> 20000 // 20sec
3 -> 60000 // 1min
4 -> 300000 // 5min
5 -> 600000 // 10min
else -> 1800000 // 30min
}.toLong()
Log.d(TAG, "Retrying in $timeStop ms")
Looper.prepare()
object : CountDownTimer(timeStop, timeStop) {
override fun onTick(millisUntilFinished: Long) {}
override fun onFinish() {
if (nFails > 0)
Log.d(TAG, "Trying to restart")
startListener(context)
}
}.start()
Looper.loop()
t?.let {
Log.d(TAG, "An error occurred: $t")
return
}
response?.let {
Log.d(TAG, "onFailure: ${it.code}")
}
StartService.nFails += 1
if (StartService.nFails > 1)
createWarningNotification(context)
val delay = when (StartService.nFails) {
1 -> 2 // 2sec
2 -> 20 // 20sec
3 -> 60 // 1min
4 -> 300 // 5min
5 -> 600 // 10min
else -> return // else keep the worker with its 20min
}.toLong()
Log.d(TAG, "Retrying in $delay s")
RestartWorker.start(context, delay = delay)
}
}

View File

@ -26,26 +26,30 @@ import org.unifiedpush.distributor.nextpush.services.NotificationUtils.createFor
import java.lang.Exception
private const val TAG = "StartService"
const val WAKE_LOCK_TAG = "NextPush:StartService:lock"
const val SERVICE_STOPPED_ACTION = "org.unifiedpush.distributor.nextpush.services.STOPPED"
var isServiceStarted = false
var nFails = 0
var wakeLock: PowerManager.WakeLock? = null
fun startListener(context: Context){
if (isServiceStarted && nFails == 0) return
Log.d(TAG, "Starting the Listener")
val serviceIntent = Intent(context, StartService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent)
}else{
context.startService(serviceIntent)
}
}
class StartService: Service(){
private var isCallbackRegistered = false
companion object {
const val WAKE_LOCK_TAG = "NextPush:StartService:lock"
const val SERVICE_STOPPED_ACTION = "org.unifiedpush.distributor.nextpush.services.STOPPED"
var isServiceStarted = false
var nFails = 0
var wakeLock: PowerManager.WakeLock? = null
private var isCallbackRegistered = false
fun startListener(context: Context){
if (isServiceStarted && nFails == 0) return
Log.d(TAG, "Starting the Listener")
Log.d(TAG, "Service is started: $isServiceStarted")
Log.d(TAG, "nFails: $nFails")
val serviceIntent = Intent(context, StartService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent)
}else{
context.startService(serviceIntent)
}
}
}
override fun onBind(intent: Intent?): IBinder? {
return null
@ -59,6 +63,7 @@ class StartService: Service(){
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(TAG, "onStartCommand")
if (!isCallbackRegistered) {
isCallbackRegistered = true
registerNetworkCallback()
@ -72,7 +77,7 @@ class StartService: Service(){
Log.d(TAG, "Destroyed")
if (isServiceStarted) {
apiDestroy()
startListener(this)
RestartWorker.start(this, delay = 0)
} else {
stopService()
}
@ -121,7 +126,9 @@ class StartService: Service(){
private val networkCallback = object : NetworkCallback() {
override fun onAvailable(network: Network) {
Log.d(TAG, "Network is CONNECTED")
startListener(this@StartService)
if (nFails > 1) {
RestartWorker.start(this@StartService, delay = 0)
}
}
override fun onCapabilitiesChanged(
@ -129,7 +136,9 @@ class StartService: Service(){
networkCapabilities: NetworkCapabilities
) {
Log.d(TAG, "Network Capabilities changed")
startListener(this@StartService)
if (nFails > 1) {
RestartWorker.start(this@StartService, delay = 0)
} // else, it retries in max 2sec
}
}