DontKillMyApp Documentation
repository·master·Indexed 20 days ago
https://github.com/urbandroid-team/dontkillmy-appA benchmarking and guidance tool for Android users to combat aggressive OEM background task restrictions. It measures how aggressively a device kills background apps by evaluating AlarmManager, main thread, and custom thread executor tasks, providing users with actionable guides to optimize device settings for better background task persistence.
What's inside DontKillMyApp
- DontKillMyApp is a tool designed to help users identify and overcome aggressive background process restrictions imposed by Android OEMs. It allows you to measure how aggressively your phone kills background apps using a benchmark, provides actionable guides to adjust your phone's settings, and enables you to share benchmark reports to help improve Android ecosystem awareness.
How the DKMA benchmark works
masterThe benchmark evaluates background task reliability by comparing executed tasks against expected tasks. It achieves this by:
- Starting a foreground service with a wake lock.
- Scheduling repetitive tasks on the main thread.
- Scheduling repetitive tasks on a custom thread executor.
- Scheduling regular alarms using
AlarmManager.setExactAndAllowWhileIdle.
Finally, the app calculates the ratio of executed tasks versus expected tasks to determine the score.
Install DontKillMyApp
masterDontKillMyApp is available on both F-Droid and Google Play Store.
- F-Droid: Get it on F-Droid
- Google Play: Get it on Google Play
Use the DKMA benchmark to measure background restrictions
masterThe DKMA benchmark measures how aggressively your phone's operating system kills background applications. You can use it to establish a baseline of your phone's performance, follow the provided setup guides to adjust your settings, and then run the benchmark again to verify if your changes improved background task persistence.How the benchmark tracks background tasks
masterThe
BenchmarkServicesimulates various Android background execution mechanisms to test device battery optimization and task killing policies. It tracks three distinct event streams:- Alarm Events: Triggered via
AlarmManagerusingACTION_ALARM. The service usessetExactAndAllowWhileIdle(on supported API levels) to schedule recurring alarms. - Main Events: Managed via a
Handlerand aRunnable(mainRunnable) that executes at a frequency defined byMAIN_REPEAT_MS. - Work Events: Managed via a
ScheduledExecutorServicethat executes at a frequency defined byWORK_REPEAT_MS.
All events are recorded into the
currentBenchmarkobject, which is persisted to disk. The benchmark automatically stops when the current time exceeds the configuredbenchmark.totimestamp.- Alarm Events: Triggered via
Configure the benchmark duration
masterThe duration of the benchmark is controlled via Android
SharedPreferences. The service reads the duration at startup using the keyKEY_BENCHMARK_DURATION. If no value is found, it defaults to the value defined byBENCHMARK_DURATION.To change the duration, update the preference associated with
KEY_BENCHMARK_DURATIONbefore starting theBenchmarkService.Share benchmark results
masterThe
ResultActivityprovides a mechanism to share benchmark results via a menu item (R.id.share). When the share action is triggered, the user is presented with a dialog containing several options:- Google Forms: Opens a browser to a specific Google Form pre-filled with device model, SDK version, and benchmark scores (Main, Alarm, and Work results).
- Email: Opens a
mailto:intent with a pre-filled subject and body containing the text report. - Text/Plain: Opens a standard Android share sheet with a text report and a bitmap image of the results view attached as an
EXTRA_STREAM.
The text report is generated using
Benchmark.generateTextReport(this, benchmark).Start the ResultActivity
masterYou can programmatically launch the
ResultActivityfrom aContextto display the benchmark results screen. This activity is configured withFLAG_ACTIVITY_SINGLE_TOPto ensure only one instance is active at the top of the stack.ResultActivity.start(context)Manage user rating prompts with RateActivity
masterThe
RateActivitycompanion object provides a programmatic interface to control when and how the application prompts the user to rate the app. This is useful for managing the lifecycle of rating requests based on user preferences and time elapsed since the last prompt.Logic Flow
shouldStartRating(context): Determines if the rating prompt should be shown. It returnstrueonly if the user hasn't already rated the app (isRateDone), hasn't selected 'Never' (isRateNever), and the cooldown period has expired (isTimeToRateAgain).start(context): The primary entry point. It checksshouldStartRatingand, if true, launches theRateActivityvia an Intent.
User State Checks
isRateDone(context): Returnstrueif the user has already clicked the rate button.isRateNever(context): Returnstrueif the user has explicitly selected the 'Never' option.isTimeToRateAgain(context): Returnstrueif the user hasn't been prompted before or if more than 7 days have passed since they selected 'Later'.
// To trigger the rating prompt logic from an Activity or Context: RateActivity.start(context)Control rating prompt timing and persistence
masterThe
RateActivitycompanion object allows you to programmatically manipulate the rating state and timing usingSharedPreferences.Methods
setRateLater(context): Records the current timestamp as the last time the user deferred the rating. This is used to implement a 7-day cooldown period.getTimeToRateAgain(context): Returns the timestamp (as aLong) of when the user last selected the 'Later' option. Returns-1Lif no such timestamp exists.
Internal Keys
Note that these methods interact with the following preference keys (internal to the app's logic):
KEY_RATE_DONE(Boolean)KEY_RATE_NEVER(Boolean)KEY_RATE_LATER(Long)
Start or stop the BenchmarkService
masterThe
BenchmarkServiceis a foreground service that executes the background task benchmark. It tracks three types of events:alarmEvents,mainEvents, andworkEventsto evaluate how well the device handles background tasks.You can control the service lifecycle using the static
startandstopmethods in theBenchmarkService.Companionobject.Note: Starting the service requires a
Contextand will trigger a foreground notification to the user.```kotlin // To start the benchmark BenchmarkService.start(context) // To stop the benchmark BenchmarkService.stop(context) ```埋