DontKillMyApp Documentation

repository·master·Indexed 20 days ago

https://github.com/urbandroid-team/dontkillmy-app

A 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.

Tokens
1.6K
Snippets
3
Records
11
Agent score
68%

What's inside DontKillMyApp

  1. Overview of DontKillMyApp

    master
    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.
  2. How the DKMA benchmark works

    master

    The benchmark evaluates background task reliability by comparing executed tasks against expected tasks. It achieves this by:

    1. Starting a foreground service with a wake lock.
    2. Scheduling repetitive tasks on the main thread.
    3. Scheduling repetitive tasks on a custom thread executor.
    4. Scheduling regular alarms using AlarmManager.setExactAndAllowWhileIdle.

    Finally, the app calculates the ratio of executed tasks versus expected tasks to determine the score.

  3. Use the DKMA benchmark to measure background restrictions

    master
    The 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.
  4. How the benchmark tracks background tasks

    master

    The BenchmarkService simulates various Android background execution mechanisms to test device battery optimization and task killing policies. It tracks three distinct event streams:

    1. Alarm Events: Triggered via AlarmManager using ACTION_ALARM. The service uses setExactAndAllowWhileIdle (on supported API levels) to schedule recurring alarms.
    2. Main Events: Managed via a Handler and a Runnable (mainRunnable) that executes at a frequency defined by MAIN_REPEAT_MS.
    3. Work Events: Managed via a ScheduledExecutorService that executes at a frequency defined by WORK_REPEAT_MS.

    All events are recorded into the currentBenchmark object, which is persisted to disk. The benchmark automatically stops when the current time exceeds the configured benchmark.to timestamp.

  5. Configure the benchmark duration

    master

    The duration of the benchmark is controlled via Android SharedPreferences. The service reads the duration at startup using the key KEY_BENCHMARK_DURATION. If no value is found, it defaults to the value defined by BENCHMARK_DURATION.

    To change the duration, update the preference associated with KEY_BENCHMARK_DURATION before starting the BenchmarkService.

  6. Share benchmark results

    master

    The ResultActivity provides 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:

    1. 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).
    2. Email: Opens a mailto: intent with a pre-filled subject and body containing the text report.
    3. 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).

  7. Manage user rating prompts with RateActivity

    master

    The RateActivity companion 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 returns true only 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 checks shouldStartRating and, if true, launches the RateActivity via an Intent.

    User State Checks

    • isRateDone(context): Returns true if the user has already clicked the rate button.
    • isRateNever(context): Returns true if the user has explicitly selected the 'Never' option.
    • isTimeToRateAgain(context): Returns true if 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)
  8. Control rating prompt timing and persistence

    master

    The RateActivity companion object allows you to programmatically manipulate the rating state and timing using SharedPreferences.

    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 a Long) of when the user last selected the 'Later' option. Returns -1L if 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)
  9. Start or stop the BenchmarkService

    master

    The BenchmarkService is a foreground service that executes the background task benchmark. It tracks three types of events: alarmEvents, mainEvents, and workEvents to evaluate how well the device handles background tasks.

    You can control the service lifecycle using the static start and stop methods in the BenchmarkService.Companion object.

    Note: Starting the service requires a Context and will trigger a foreground notification to the user.

    ```kotlin
    // To start the benchmark
    BenchmarkService.start(context)
    
    // To stop the benchmark
    BenchmarkService.stop(context)
    ```埋