Mitigation Strategy: Always Dispose Subscriptions
-
Description:
- Identify Subscription Points: Locate all instances where
subscribe()
is called on anObservable
orFlowable
. - Use
CompositeDisposable
(Recommended):- Create a
CompositeDisposable
instance. - Add each
Disposable
returned bysubscribe()
to theCompositeDisposable
usingcompositeDisposable.add(disposable)
. - In the appropriate lifecycle method, call
compositeDisposable.clear()
orcompositeDisposable.dispose()
.
- Create a
- Use
Disposable.dispose()
(Alternative): Store theDisposable
and calldisposable.dispose()
directly when needed. - Use Automatic Disposal Operators: Prefer operators like
takeUntil()
,takeWhile()
, ortake(n)
to automatically limit the subscription's lifetime based on anotherObservable
or a condition. using()
for Resource Management: Useusing()
to tie the lifetime of a resource directly to anObservable
's.
- Identify Subscription Points: Locate all instances where
-
Threats Mitigated:
- Memory Leaks (Severity: High): Prevents
Observable
s from holding onto subscribers indefinitely. - Thread Starvation (Severity: High): Releases threads held by subscriptions.
- Unintended Side Effects (Severity: Medium): Prevents continued execution of
Observable
logic after it's no longer needed. - Resource Exhaustion (Severity: High): Releases resources held by the subscription.
- Memory Leaks (Severity: High): Prevents
-
Impact:
- Memory Leaks: Risk reduced to near zero.
- Thread Starvation: Risk significantly reduced.
- Unintended Side Effects: Risk significantly reduced.
- Resource Exhaustion: Risk significantly reduced.
-
Currently Implemented:
MainActivity
: UsesCompositeDisposable
andclear()
inonDestroy()
.NetworkService
: UsestakeUntil()
for lifecycle management.DataRepository
: Usesusing()
for database connections.
-
Missing Implementation:
BackgroundSyncService
: Missing explicit disposal; needsCompositeDisposable
.- Utility classes with static
Observable
s: Need review.
Mitigation Strategy: Careful Scheduler Selection and Management
-
Description:
- Understand Schedulers: Familiarize yourself with RxJava schedulers (
Schedulers.io()
,Schedulers.computation()
,Schedulers.single()
,Schedulers.newThread()
,Schedulers.trampoline()
,AndroidSchedulers.mainThread()
, etc.). - Choose Appropriately: Select the scheduler that best matches the type of work. Avoid
Schedulers.newThread()
unless absolutely necessary. - Use
subscribeOn()
: Specify the scheduler for the subscription logic. - Use
observeOn()
: Specify the scheduler for the subscriber (receiving items). - Avoid Blocking Operations: Never perform blocking operations on the main thread. Use
subscribeOn()
andobserveOn()
appropriately. - Custom Schedulers (Rare): If needed, ensure they use a bounded thread pool.
- Understand Schedulers: Familiarize yourself with RxJava schedulers (
-
Threats Mitigated:
- Thread Starvation (Severity: High): Prevents excessive thread creation.
- Application Unresponsiveness (Severity: High): Prevents blocking the main thread.
- Deadlocks (Severity: High): Proper scheduler usage helps avoid deadlocks.
-
Impact:
- Thread Starvation: Risk significantly reduced.
- Application Unresponsiveness: Risk eliminated with correct usage.
- Deadlocks: Risk reduced.
-
Currently Implemented:
NetworkService
: UsesSchedulers.io()
.ImageProcessingUtil
: UsesSchedulers.computation()
.- UI updates use
observeOn(AndroidSchedulers.mainThread())
.
-
Missing Implementation:
DatabaseService
: Some operations on the main thread; needsSchedulers.io()
.FileDownloadUtil
: UsesSchedulers.newThread()
; should useSchedulers.io()
.
Mitigation Strategy: Always Provide an onError
Handler
-
Description:
- Mandatory
onError
: Everysubscribe()
call must include anonError
handler. - Handle the Exception: The
onError
handler should:- Log the error.
- Attempt recovery (optional).
- Inform the user (optional).
- Clean up (optional).
- Avoid Re-throwing (Generally): Do not re-throw unless handled further up.
- Consider Error Handling Operators: Use operators like
onErrorReturnItem()
,onErrorResumeNext()
,retry()
,retryWhen()
, oronErrorComplete()
within theObservable
chain.
- Mandatory
-
Threats Mitigated:
- Application Crashes (Severity: High): Prevents unhandled exceptions.
- Undefined Behavior (Severity: High): Ensures graceful error handling.
- Data Loss (Severity: Medium): Allows for retries or fallbacks.
- Security Vulnerabilities (Severity: Low/Medium): Indirectly reduces risk.
-
Impact:
- Application Crashes: Risk reduced to near zero.
- Undefined Behavior: Risk significantly reduced.
- Data Loss: Risk reduced.
- Security Vulnerabilities: Indirectly reduces risk.
-
Currently Implemented:
NetworkService
:onError
handlers log errors and show messages.DataRepository
:onError
handlers attempt retries and log failures.
-
Missing Implementation:
- Utility classes: Missing
onError
handlers in somesubscribe()
calls. BackgroundSyncService
: Inconsistent error handling.
- Utility classes: Missing
Mitigation Strategy: Use doOn...
Operators for Debugging
-
Description:
- Identify Debugging Points: Determine where to inspect the
Observable
stream. - Insert
doOn...
Operators: Add operators likedoOnNext()
,doOnError()
,doOnComplete()
,doOnSubscribe()
,doOnDispose()
,doOnTerminate()
. - Log or Inspect: Log information or use a debugger.
- Remove After Debugging (Optional): Remove or comment out after debugging.
- Identify Debugging Points: Determine where to inspect the
-
Threats Mitigated:
- Complex, Difficult-to-Debug Code (Severity: Medium): Allows inspection without affecting behavior.
-
Impact:
- Complex, Difficult-to-Debug Code: Greatly simplifies debugging.
-
Currently Implemented:
- Used sporadically.
-
Missing Implementation:
- No consistent strategy.
Mitigation Strategy: Minimize Side Effects within Operators
-
Description:
- Identify Side Effects: Examine operators like
map()
,flatMap()
, andfilter()
for operations modifying external state. - Refactor for Purity:
map()
andflatMap()
for Transformations: Use these for data transformation only.doOn...
for Explicit Side Effects: If unavoidable, usedoOnNext()
,doOnError()
, ordoOnComplete()
to make them explicit.subscribe()
for Final Actions: Usesubscribe()
for final actions like UI updates.
- Isolate Side Effects: Encapsulate complex side effects in separate methods/classes.
- Consider Immutable Data: Use immutable data structures.
- Identify Side Effects: Examine operators like
-
Threats Mitigated:
- Unexpected Behavior (Severity: Medium): Reduces unintended consequences.
- Difficult Debugging (Severity: Medium): Improves code clarity.
- Concurrency Issues (Severity: Medium): Reduces race conditions.
-
Impact:
- Unexpected Behavior: Significantly reduces risk.
- Difficult Debugging: Improves clarity.
- Concurrency Issues: Reduces risk.
-
Currently Implemented:
- Some effort in
DataRepository
.
- Some effort in
-
Missing Implementation:
BackgroundSyncService
and UI components: Side effects withinmap()
andflatMap()
.
Mitigation Strategy: Prefer Observables/Flowables, Limit Subject Scope, Choose the Right Subject Type, Avoid Manual onNext() Calls, Consider Alternatives
-
Description:
- Favor Observables/Flowables: Prioritize
Observable.create()
,Observable.fromCallable()
, etc. - Encapsulate Subjects: Keep Subjects private; expose only the
Observable
interface. - Select Appropriate Subject Type: Choose
PublishSubject
,BehaviorSubject
,ReplaySubject
, orAsyncSubject
based on needs. - Centralize Emission Logic: Avoid calling
onNext()
,onError()
,onComplete()
from multiple locations. - Explore Alternatives: Consider
share()
,publish().refCount()
, or event bus libraries.
- Favor Observables/Flowables: Prioritize
-
Threats Mitigated:
- Tight Coupling (Severity: Medium): Reduces dependencies.
- Difficult Debugging (Severity: Medium): Improves data flow understanding.
- Unexpected Behavior (Severity: Medium): Reduces unintended consequences.
- Concurrency Issues (Severity: Medium): Reduces race conditions.
-
Impact:
- Tight Coupling: Significantly reduces coupling.
- Difficult Debugging: Improves clarity.
- Unexpected Behavior: Reduces risk.
- Concurrency Issues: Reduces risk.
-
Currently Implemented:
DataRepository
uses Subjects internally, exposes Observables.
-
Missing Implementation:
BackgroundSyncService
: Extensive, public Subject use.- UI components: Subjects used as a simple event bus.