Skip to content
This repository was archived by the owner on Dec 18, 2022. It is now read-only.

Commit 96fb493

Browse files
authored
Merge pull request #72 from 05nelsonm/mn/bug-fix/tor-service-controller-builder-exception-handling
Mn/bug fix/tor service controller builder exception handling
2 parents ccb8e61 + 02f92fd commit 96fb493

File tree

8 files changed

+96
-80
lines changed

8 files changed

+96
-80
lines changed

sampleapp/src/main/java/io/matthewnelson/sampleapp/App.kt

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,8 @@ class App: Application() {
163163
stopServiceTimeDelay: Long,
164164
stopServiceOnTaskRemoved: Boolean,
165165
buildConfigDebug: Boolean
166-
) {
167-
TorServiceController.Builder(
166+
): TorServiceController.Builder {
167+
return TorServiceController.Builder(
168168
application = application,
169169
torServiceNotificationBuilder = serviceNotificationBuilder,
170170
backgroundManagerPolicy = backgroundManagerPolicy,
@@ -178,7 +178,6 @@ class App: Application() {
178178
.disableStopServiceOnTaskRemoved(stopServiceOnTaskRemoved)
179179
.setBuildConfigDebug(buildConfigDebug)
180180
.setEventBroadcaster(eventBroadcaster = MyEventBroadcaster())
181-
.build()
182181
}
183182
}
184183

@@ -196,8 +195,8 @@ class App: Application() {
196195

197196
stopTorDelaySettingAtAppStartup = LibraryPrefs.getControllerStopDelaySetting(prefs).toString()
198197

199-
try {
200-
setupTorServices(
198+
199+
val builder = setupTorServices(
201200
this,
202201
serviceNotificationBuilder,
203202
generateBackgroundManagerPolicy(prefs),
@@ -206,20 +205,36 @@ class App: Application() {
206205
LibraryPrefs.getControllerDisableStopServiceOnTaskRemovedSetting(prefs),
207206
LibraryPrefs.getControllerBuildConfigDebugSetting(prefs)
208207
)
209-
210-
TorServiceController.appEventBroadcaster?.let {
211-
(it as MyEventBroadcaster).broadcastLogMessage(
212-
"SampleApp|Application|Process ID: ${Process.myPid()}"
213-
)
214-
}
208+
try {
209+
builder.build()
215210
} catch (e: Exception) {
216211
e.message?.let {
217212
DashboardFragment.showMessage(
218213
DashMessage(
219-
"${DashMessage.EXCEPTION}$it", R.drawable.dash_message_color_red, 5_000
214+
"${DashMessage.EXCEPTION}$it",
215+
R.drawable.dash_message_color_red,
216+
5_000
220217
)
221218
)
222219
}
220+
221+
// Would not normally need any of this, but b/c the sample application allows for
222+
// modifying these settings to show off capabilities, it's necessary.
223+
setupTorServices(
224+
this,
225+
serviceNotificationBuilder,
226+
generateBackgroundManagerPolicy(prefs, BackgroundPolicy.RUN_IN_FOREGROUND, true),
227+
LibraryPrefs.getControllerRestartDelaySetting(prefs),
228+
stopTorDelaySettingAtAppStartup.toLong(),
229+
LibraryPrefs.getControllerDisableStopServiceOnTaskRemovedSetting(prefs),
230+
LibraryPrefs.getControllerBuildConfigDebugSetting(prefs)
231+
).build()
232+
}
233+
234+
TorServiceController.appEventBroadcaster?.let {
235+
(it as MyEventBroadcaster).broadcastLogMessage(
236+
"SampleApp|Application|Process ID: ${Process.myPid()}"
237+
)
223238
}
224239
}
225240
}

sampleapp/src/main/java/io/matthewnelson/sampleapp/ui/fragments/home/HomeFragment.kt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,7 @@ class HomeFragment : Fragment() {
106106
torServicePrefs = TorServicePrefs(inflater.context)
107107
hasDebugLogs = torServicePrefs.getBoolean(
108108
ServiceConsts.PrefKeyBoolean.HAS_DEBUG_LOGS,
109-
try {
110-
TorServiceController.getTorSettings().hasDebugLogs
111-
} catch (e: RuntimeException) {
112-
false
113-
}
109+
TorServiceController.getTorSettings().hasDebugLogs
114110
)
115111
return inflater.inflate(R.layout.fragment_home, container, false)
116112
}

sampleapp/src/main/java/io/matthewnelson/sampleapp/ui/fragments/settings/library/SettingsLibraryFragment.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ class SettingsLibraryFragment : Fragment() {
152152
controllerOptions.getStopDelayTime(),
153153
controllerOptions.disableStopServiceOnTaskRemoved,
154154
controllerOptions.buildConfigDebug
155-
)
155+
).build()
156156
} catch (e: Exception) {
157157
e.message?.let {
158158
val msg = if (it.contains(BackgroundPolicy.RUN_IN_FOREGROUND))

topl-service/src/main/java/io/matthewnelson/topl_service/TorServiceController.kt

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -131,18 +131,11 @@ class TorServiceController private constructor(): ServiceConsts() {
131131
private val torServiceNotificationBuilder: ServiceNotification.Builder,
132132
private val backgroundManagerPolicy: BackgroundManager.Builder.Policy,
133133
private val buildConfigVersionCode: Int,
134-
torSettings: TorSettings,
134+
private val torSettings: TorSettings,
135135
private val geoipAssetPath: String,
136136
private val geoip6AssetPath: String
137137
) {
138138

139-
init {
140-
// Ensure TorSettings gets initialized no matter if exceptions are thrown
141-
// elsewhere in the builder
142-
BaseService.initializTorSettings(torSettings)
143-
}
144-
145-
private var appEventBroadcaster: TorServiceEventBroadcaster? = Companion.appEventBroadcaster
146139
// private var heartbeatTime = BackgroundManager.heartbeatTime
147140
private var restartTorDelayTime = ServiceActionProcessor.restartTorDelayTime
148141
private var stopServiceDelayTime = ServiceActionProcessor.stopServiceDelayTime
@@ -203,24 +196,10 @@ class TorServiceController private constructor(): ServiceConsts() {
203196
* When your task is removed from the Recent App's tray, [TorService.onTaskRemoved] is
204197
* triggered. Default behaviour is to stop Tor, and then [TorService]. Electing this
205198
* option will inhibit the default behaviour from being carried out.
206-
*
207-
* @throws [IllegalArgumentException] If your selected [BackgroundManager.Builder.Policy]
208-
* is *not* [ServiceConsts.BackgroundPolicy.RUN_IN_FOREGROUND], or if
209-
* [BackgroundManager.Builder.killAppIfTaskIsRemoved] is *not* `true`
210199
* */
211200
@JvmOverloads
212-
@Throws(IllegalArgumentException::class)
213201
fun disableStopServiceOnTaskRemoved(disable: Boolean = true): Builder {
214-
if (disable) {
215-
val policy = backgroundManagerPolicy.policyBuilder.chosenPolicy
216-
val killApp = backgroundManagerPolicy.policyBuilder.killAppIfTaskIsRemoved
217-
require(policy == BackgroundPolicy.RUN_IN_FOREGROUND && killApp) {
218-
"BackgroundManager's selected Policy must be " +
219-
"${BackgroundPolicy.RUN_IN_FOREGROUND}, and killAppIfTaskIsRemoved must " +
220-
"be set to true."
221-
}
222-
stopServiceOnTaskRemoved = !disable
223-
}
202+
stopServiceOnTaskRemoved = !disable
224203
return this
225204
}
226205

@@ -275,7 +254,8 @@ class TorServiceController private constructor(): ServiceConsts() {
275254
* class actually is.
276255
* */
277256
fun setEventBroadcaster(eventBroadcaster: TorServiceEventBroadcaster): Builder {
278-
this.appEventBroadcaster = eventBroadcaster
257+
if (Companion.appEventBroadcaster == null)
258+
appEventBroadcaster = eventBroadcaster
279259
return this
280260
}
281261

@@ -302,19 +282,21 @@ class TorServiceController private constructor(): ServiceConsts() {
302282
* [Companion] object w/o throwing exceptions.
303283
*
304284
* See [Builder] for code samples.
285+
*
286+
* @throws [IllegalArgumentException] If [disableStopServiceOnTaskRemoved] was elected
287+
* and your selected [BackgroundManager.Builder.Policy] is **not**
288+
* [ServiceConsts.BackgroundPolicy.RUN_IN_FOREGROUND] and/or
289+
* [BackgroundManager.Builder.killAppIfTaskIsRemoved] is **not** `true`
305290
* */
306291
fun build() {
307292

308-
// If `BaseService.application` has been initialized
309-
// already, return as to not overwrite things.
310-
try {
311-
BaseService.getAppContext()
312-
return
313-
} catch (e: RuntimeException) {}
293+
// Must be called before application gets set
294+
ServiceActionProcessor.initialize(restartTorDelayTime, stopServiceDelayTime)
314295

315296
BaseService.initialize(
316297
application,
317298
buildConfigVersionCode,
299+
torSettings,
318300
buildConfigDebug,
319301
geoipAssetPath,
320302
geoip6AssetPath,
@@ -323,13 +305,16 @@ class TorServiceController private constructor(): ServiceConsts() {
323305
)
324306

325307
// BackgroundManager.initialize(heartbeatTime)
326-
ServiceActionProcessor.initialize(restartTorDelayTime, stopServiceDelayTime)
327-
328-
Companion.appEventBroadcaster = this.appEventBroadcaster
329-
330308
torServiceNotificationBuilder.build(application.applicationContext)
331309

332-
backgroundManagerPolicy.build()
310+
if (backgroundManagerPolicy.configurationIsCompliant(stopServiceOnTaskRemoved))
311+
backgroundManagerPolicy.build()
312+
else
313+
throw IllegalArgumentException(
314+
"disableStopServiceOnTaskRemoved requires a BackgroundManager Policy of " +
315+
"${BackgroundPolicy.RUN_IN_FOREGROUND}, and " +
316+
"killAppIfTaskIsRemoved must be set to true."
317+
)
333318
}
334319
}
335320

@@ -345,6 +330,9 @@ class TorServiceController private constructor(): ServiceConsts() {
345330
/**
346331
* Get the [TorConfigFiles] that have been set after calling [Builder.build]
347332
*
333+
* This method will *never* throw the [RuntimeException] if you call it after
334+
* [Builder.build].
335+
*
348336
* @return Instance of [TorConfigFiles] that are being used throughout TOPL-Android
349337
* @throws [RuntimeException] if called before [Builder.build]
350338
* */
@@ -359,15 +347,13 @@ class TorServiceController private constructor(): ServiceConsts() {
359347
}
360348

361349
/**
362-
* Get the [TorSettings] that have been set after instantiating [Builder]. These are
363-
* the [TorSettings] you initialized [TorServiceController.Builder] with.
350+
* Get the [TorSettings] that have been set after calling [Builder.build].
364351
*
365352
* This method will *never* throw the [RuntimeException] if you call it after
366-
* you have instantiated the [Builder] object, as [TorSettings] are set immediately
367-
* via [BaseService.initializTorSettings].
353+
* [Builder.build].
368354
*
369355
* @return Instance of [TorSettings] that are being used throughout TOPL-Android
370-
* @throws [RuntimeException] if called before [Builder] is instantiated
356+
* @throws [RuntimeException] if called before [Builder.build]
371357
* */
372358
@JvmStatic
373359
@Throws(RuntimeException::class)

topl-service/src/main/java/io/matthewnelson/topl_service/lifecycle/BackgroundManager.kt

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@
6767
package io.matthewnelson.topl_service.lifecycle
6868

6969
import android.content.Context
70-
import android.os.Process
7170
import androidx.lifecycle.Lifecycle
7271
import androidx.lifecycle.LifecycleObserver
7372
import androidx.lifecycle.OnLifecycleEvent
@@ -77,6 +76,7 @@ import io.matthewnelson.topl_service.service.TorService
7776
import io.matthewnelson.topl_service.service.components.actions.ServiceActionProcessor
7877
import io.matthewnelson.topl_service.service.components.binding.TorServiceConnection
7978
import io.matthewnelson.topl_service.util.ServiceConsts
79+
import kotlin.system.exitProcess
8080

8181
/**
8282
* When your application is sent to the background (the Recent App's tray or lock screen), the
@@ -151,9 +151,9 @@ class BackgroundManager internal constructor(
151151
class Builder {
152152

153153
@BackgroundPolicy
154-
internal lateinit var chosenPolicy: String
154+
private lateinit var chosenPolicy: String
155155
private var executionDelay: Long = 30_000L
156-
internal var killAppIfTaskIsRemoved = false
156+
private var killAppIfTaskIsRemoved = false
157157

158158
/**
159159
* Stops [TorService] after being in the background for the declared [secondsFrom5To45].
@@ -221,7 +221,16 @@ class BackgroundManager internal constructor(
221221
*
222222
* @param [policyBuilder] The [BackgroundManager.Builder] to be built during initialization
223223
* */
224-
class Policy(internal val policyBuilder: Builder) {
224+
class Policy internal constructor (private val policyBuilder: Builder) {
225+
226+
internal fun configurationIsCompliant(stopServiceOnTaskRemoved: Boolean): Boolean {
227+
return if (!stopServiceOnTaskRemoved) {
228+
policyBuilder.chosenPolicy == BackgroundPolicy.RUN_IN_FOREGROUND &&
229+
policyBuilder.killAppIfTaskIsRemoved
230+
} else {
231+
true
232+
}
233+
}
225234

226235
/**
227236
* Only available internally, so this is where we intercept for integration testing.
@@ -257,7 +266,7 @@ class BackgroundManager internal constructor(
257266

258267
@JvmStatic
259268
@Volatile
260-
var taskIsInForeground = true
269+
var taskIsInForeground = false
261270
private set
262271

263272
@JvmStatic
@@ -281,7 +290,7 @@ class BackgroundManager internal constructor(
281290
* */
282291
internal fun killAppProcess() {
283292
if (backgroundManager.killAppIfTaskIsRemoved && taskIsRemovedFromRecentApps) {
284-
Process.killProcess(Process.myPid())
293+
exitProcess(0)
285294
}
286295
}
287296
}

topl-service/src/main/java/io/matthewnelson/topl_service/notification/ServiceNotification.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,14 @@ class ServiceNotification internal constructor(
339339
* [io.matthewnelson.topl_service.TorServiceController.Builder.build]
340340
* */
341341
internal fun build(context: Context) {
342-
Companion.serviceNotification = this.serviceNotification
343-
Companion.serviceNotification.setupNotificationChannel(context)
342+
// Only initialize it once. Reflection has issues here
343+
// as it's in a Companion object.
344+
try {
345+
Companion.serviceNotification.hashCode()
346+
} catch (e: UninitializedPropertyAccessException) {
347+
Companion.serviceNotification = this.serviceNotification
348+
Companion.serviceNotification.setupNotificationChannel(context)
349+
}
344350
}
345351

346352
}

topl-service/src/main/java/io/matthewnelson/topl_service/service/BaseService.kt

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -114,27 +114,26 @@ internal abstract class BaseService: Service() {
114114
var stopServiceOnTaskRemoved: Boolean = true
115115
private set
116116

117-
fun initializTorSettings(settings: TorSettings) {
118-
if (!::torSettings.isInitialized)
119-
torSettings = settings
120-
}
121-
122117
fun initialize(
123118
application: Application,
124119
buildConfigVersionCode: Int,
120+
torSettings: TorSettings,
125121
buildConfigDebug: Boolean,
126122
geoipAssetPath: String,
127123
geoip6AssetPath: String,
128124
torConfigFiles: TorConfigFiles,
129125
stopServiceOnTaskRemoved: Boolean
130126
) {
131-
this.application = application
132-
this.buildConfigVersionCode = buildConfigVersionCode
133-
this.buildConfigDebug = buildConfigDebug
134-
this.geoipAssetPath = geoipAssetPath
135-
this.geoip6AssetPath = geoip6AssetPath
136-
this.torConfigFiles = torConfigFiles
137-
this.stopServiceOnTaskRemoved = stopServiceOnTaskRemoved
127+
if (this.application == null) {
128+
this.application = application
129+
this.buildConfigVersionCode = buildConfigVersionCode
130+
this.torSettings = torSettings
131+
this.buildConfigDebug = buildConfigDebug
132+
this.geoipAssetPath = geoipAssetPath
133+
this.geoip6AssetPath = geoip6AssetPath
134+
this.torConfigFiles = torConfigFiles
135+
this.stopServiceOnTaskRemoved = stopServiceOnTaskRemoved
136+
}
138137
}
139138

140139
@Throws(RuntimeException::class)

topl-service/src/main/java/io/matthewnelson/topl_service/service/components/actions/ServiceActionProcessor.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,13 @@ internal class ServiceActionProcessor(private val torService: BaseService): Serv
9090
private set
9191

9292
fun initialize(restartMilliseconds: Long, stopServiceMilliseconds: Long) {
93-
restartTorDelayTime = restartMilliseconds
94-
stopServiceDelayTime = stopServiceMilliseconds
93+
// Only initialize it once.
94+
try {
95+
BaseService.getAppContext()
96+
} catch (e: RuntimeException) {
97+
restartTorDelayTime = restartMilliseconds
98+
stopServiceDelayTime = stopServiceMilliseconds
99+
}
95100
}
96101

97102
//////////////////////////

0 commit comments

Comments
 (0)