Home · ASPLOS 2023 · Mobile, Edge & Embedded

Transparent Runtime Change Handling for Android Apps

Zizhan Chen and Zili Shao

Conference
ASPLOS 2023
Published
2023
Pages
756-770
Citations
1

When you rotate your phone, resize a window, or switch language, Android throws away and recreates the running screen (Activity) to reload the right resources, which forces every app developer to manually save and restore state or risk losing it or crashing; this paper (Hong Kong Polytechnic University — Zizhan Chen, Zili Shao) presents RCHDroid, a system-level approach that instead of restarting builds a new activity for the new configuration and migrates the live state from the old one into it, keeping the old activity in an inactive mode, and uses a lazy-migration scheme that carries the results of still-running background tasks over when they finish — so existing apps survive configuration changes with no code changes and handle them 25.46 percent faster.

The argument in one glance

  1. Problem

    Rotating your phone can lose an app's state or crash it, because Android restarts the screen

    Mobile devices constantly face runtime configuration changes: you rotate the screen, resize a window in split-screen or on a foldable, or switch the system language. Android responds to such a change by reloading the resources (layouts, strings, images) that match the new configuration, and the way it does this is drastic: it destroys and restarts the currently running Activity — the object representing the on-screen page — so the new resources are loaded from scratch. The consequence is that whatever state the activity held in memory (form fields, scroll position, in-progress work) is wiped when it is destroyed, unless the developer has explicitly saved it and restored it in the new instance. So a simple screen rotation becomes a moment where an app can lose the user's state or, if the developer handled it wrong, crash outright.

  2. What people did

    Make developers save and restore state across the restart

    Android's design puts the burden on the application developer: before the activity is destroyed, the app must save its important state (using the framework's save-state callbacks), and when the new activity is created, it must restore that state. Done correctly, this preserves the user's data across the restart, and it is the standard, expected way apps are supposed to handle configuration changes.

  3. Why it fell short

    Manual save-and-restore is error-prone, and the restart itself is slow

    Relying on developers to save and restore state is fragile. It is easy to forget to save some piece of state, to save it incompletely, or to mishandle the restore, and the failure only shows up when a user happens to rotate the screen at the wrong moment — leading to lost state or crashes that are a well-known, pervasive class of Android bugs. Asynchronous work makes it worse: background tasks tied to the old activity may still be running when it is destroyed, so their results are lost or, if they try to update a dead activity, cause errors. And beyond correctness, destroying and rebuilding the whole activity is wasteful, spending time tearing down and reconstructing objects that mostly did not need to change. What is missing is a way to handle configuration changes correctly and efficiently without asking every developer to get the save-and-restore dance right, and without losing in-flight asynchronous work.

  4. This paper's idea

    Don't restart — build a new activity and migrate the live state into it

    RCHDroid is a transparent, system-level approach that handles runtime configuration changes without restarting the activity and without any changes to the app. When a configuration change occurs, instead of destroying the current activity, RCHDroid creates a new activity configured for the new settings and migrates the live state directly from the old activity into the new one, then puts the old activity into an inactive mode rather than tearing it down. Because the migration happens at the Android system level, existing apps get correct state preservation for free, with no developer effort. For the hard case of asynchronous tasks that are still running on the old activity when the change happens, RCHDroid uses a lazy-migration scheme: it lets those tasks keep running on the old (now inactive) activity, and when a task returns, it migrates the result event over to the new activity, so in-flight background work is not lost and lands where it belongs. The authors implemented a prototype on real hardware and released the source; with RCHDroid, existing apps handle runtime configuration changes without modification and cut the runtime-change handling time by 25.46 percent.

Why this problem is worth solving

Configuration changes are among the most common and most bug-prone events in an Android app’s life, so handling them well matters for nearly every app.

A configuration change is any shift in the environment an Android app runs in that affects which resources it should use: rotating the device changes the screen orientation and therefore the layout; entering split-screen or unfolding a foldable resizes the window; changing the system language switches which string and image resources apply. Android apps are built around resources selected by configuration — you provide a portrait layout and a landscape layout, English strings and French strings — and the framework picks the right ones for the current configuration. When the configuration changes, the currently displayed resources are no longer the right ones, so the framework must reload them. Android’s chosen mechanism is to destroy the running Activity (the component managing a screen) and create it again, so that during recreation it naturally loads the resources matching the new configuration. This is simple and uniform, but it has a severe side effect: an activity holds in-memory state, and destroying it discards that state. The framework offers callbacks to save and restore a bundle of state across the restart, but using them correctly is entirely the developer’s responsibility. Because rotation and resizing happen all the time, and because getting the save-restore logic exactly right for all of an app’s state is genuinely hard, mishandled configuration changes are one of the most common sources of state-loss and crash bugs in Android, which is why a better mechanism would help a huge number of apps.

The reason the manual approach is so troublesome is that it pushes a subtle, cross-cutting concern onto every developer, and asynchronous work makes it genuinely hard.

Handling a configuration change correctly requires the developer to enumerate every piece of state the activity holds that must survive, serialize it into the save-state bundle before destruction, and faithfully reconstruct it afterward — for all of the app’s screens and all of its state. Any omission is a latent bug that surfaces only when a user triggers a change at the wrong time, and such bugs are hard to notice in testing because they depend on timing and on which state happens to matter. Asynchronous tasks sharpen the difficulty. Apps do work in the background — network requests, database queries, computations — that is logically tied to the activity that started it and expects to deliver its result back to that activity. When a configuration change destroys the activity mid-task, the task is left pointing at a destroyed object: its result may be dropped, or delivering it may touch dead state and cause a crash. Correctly handling this by hand means tracking every in-flight task, cancelling or rebinding it, and routing its eventual result to the new activity, which is intricate and easy to get wrong. So the problem is not just save-and-restore of static state, but also the graceful handoff of live, in-progress work across the change. A system-level mechanism that migrates both the state and the pending work, transparently, removes this whole class of burden from developers, which is the opportunity RCHDroid pursues.

What people did before, and where it broke

  • Restart the activity and rely on manual save-restore. Android’s default: destroy the activity, recreate it, and have the developer save and restore state via framework callbacks. Where it broke. It is error-prone — missed or incomplete state handling causes state loss and crashes — and it burdens every developer with getting it right.
  • Declare the activity handles the change itself. Let an activity opt out of the restart and handle the configuration change manually in code. Where it broke. This still requires developer effort per activity, is easy to get wrong for complex resource changes, and does not solve the problem for the many apps that do not use it.
  • Ignore or suppress configuration changes. Lock orientation or otherwise avoid triggering changes. Where it broke. It degrades the user experience and does not address resizing, language changes, or the general case; it sidesteps rather than solves the problem.
  • Prior state-preservation tools requiring app changes. Approaches that identify and preserve app state but need the app to be modified or rebuilt. Where it broke. They are not transparent, so they cannot help the enormous body of existing, unmodified apps.
  • The gap. No approach handled configuration changes transparently at the system level — migrating an activity’s live state, and the results of its still-running asynchronous tasks, to a new correctly-configured activity — so that existing apps got correct, efficient handling with no modification.

How RCHDroid works

Migrating state to a new activity instead of restarting on a configuration change

  1. new

  2. new

  3. new

  4. new

  5. new

The idea

Move the work from the developer to the system, so it is done once and correctly. The central choice in RCHDroid is to make configuration-change handling a transparent, system-level service rather than a per-app developer responsibility. Android’s design distributes a subtle correctness concern across every app, where it is repeatedly gotten wrong; RCHDroid centralizes it in the framework, so the migration of state on a configuration change happens automatically and existing apps inherit correct behavior with no code changes. Solving a pervasive correctness problem once, in the system layer, so that unmodified applications benefit transparently rather than each having to handle it, is the same system-level-transparency philosophy the work on faster mobile app hot-launch through fore-background awareness covered elsewhere on this site is built on, improving apps from beneath without asking them to change. RCHDroid applies that philosophy to the configuration-change lifecycle, which is exactly the place Android had offloaded the hardest work onto developers.

Migrate the live state instead of destroying and rebuilding it. The mechanism that makes transparency possible is migration: rather than tearing down the activity and asking the app to reconstruct its state, RCHDroid builds the correctly-configured new activity and copies the old activity’s live state into it. This preserves exactly what the user had, and it avoids the wasted work of destroying and recreating everything, which is why it is also faster. Capturing a running component’s live in-memory state and moving it intact to a new context, rather than losing it and rebuilding from scratch, is the same state-preservation instinct the work on micro-checkpoints as a data single-level store covered elsewhere on this site embodies, treating live program state as something to be captured and carried rather than reconstructed. RCHDroid captures and migrates an activity’s state across a configuration change so the transition is seamless.

Let in-flight work finish and reconcile its result lazily. The subtlest part is asynchronous tasks that are still running when the change happens, and RCHDroid’s answer is not to block or cancel them but to let them complete on the old, inactive activity and lazily route their results to the new one. This keeps the transition from stalling on background work and prevents both lost results and crashes from delivering to a destroyed activity. Allowing concurrent, in-progress work to proceed without stalling the main transition and reconciling its outcome when it lands is the same non-blocking discipline the work on persistent concurrent checkpointing for machine learning covered elsewhere on this site pursues, letting ongoing computation continue while state is handled around it. RCHDroid brings that discipline to the Android lifecycle, so a configuration change does not have to wait for, or abandon, the app’s background tasks.

Following a rotation through RCHDroid

Rotating the screen while a background task is running

An illustrative trace, based on the paper's abstract, of how RCHDroid handles a configuration change with an in-flight async task. Internal details beyond the abstract were not available for this draft.

Step 1 of 5

The user rotates the device mid-task

An app is showing a screen and has a background task running (say, loading data). The user rotates the device, triggering a configuration change. Android would normally destroy this activity and recreate it, endangering both the on-screen state and the running task.

The rotation is a configuration change requiring new (landscape) resources.

Why it works

  • Migrating state avoids the loss that restarting causes. Destroying the activity discards its in-memory state unless the app saved it → but building a new activity and copying the live state over preserves it directly → so state loss is prevented without any developer save-restore code.
  • Doing it in the system makes it transparent. Per-app handling means every developer must get it right → but performing the migration at the Android system level applies it uniformly → so existing, unmodified apps get correct handling for free.
  • Keeping the old activity alive rescues in-flight work. Destroying the activity orphans its running async tasks, losing results or crashing → but placing it in an inactive mode lets those tasks keep running against a live object → so background work is not abandoned.
  • Lazy result migration reconciles async tasks correctly. Routing a finished task’s result to a destroyed activity fails → but migrating the result event to the new activity when the task returns delivers it safely → so in-flight results land where they belong.
  • Avoiding teardown and rebuild is faster. Restarting spends time destroying and reconstructing objects that mostly did not change → but migrating state into a new activity skips most of that work → so handling time drops by 25.46 percent.

What it costs (trade-offs and scope)

  • This is a draft built from the paper’s abstract. The full paper was behind a publisher access wall for this draft (no arXiv version, no open-access or author copy located, and the ACM Digital Library returned a bot-verification challenge), so this account is assembled from the paper’s complete abstract plus standard background on the Android activity lifecycle. The exact state-migration mechanism, how the system identifies and copies live state, the inactive-mode and lazy-migration implementation, the compatibility scope, and the evaluation setup are not reproduced here and should be read from the paper.
  • Keeping old activities alive uses resources. Placing the old activity in an inactive mode instead of destroying it, and keeping its async tasks running, consumes memory and possibly compute until those tasks complete; the abstract does not detail this overhead, and it is a trade against the restart-based approach’s immediate teardown.
  • The reported speedup is the abstract’s own figure. The 25.46 percent reduction in runtime-change handling time is the abstract’s result; the workloads, apps, devices, and baseline behind it are not detailed in this draft.
  • Transparent migration must handle every kind of state and edge case correctly. Migrating arbitrary live state and reconciling arbitrary async results at the system level is delicate; how RCHDroid handles the full range of app state, resource-dependent objects, and unusual task patterns, and whether any apps are incompatible, is exactly the kind of detail the abstract cannot convey and that should be confirmed in the paper.
  • It targets Android configuration changes specifically. RCHDroid addresses runtime configuration changes (orientation, resizing, language) in Android; other platforms and other kinds of lifecycle events are outside its stated scope.

The evaluation

Handling an Android runtime configuration change

PropertyRestart plus manual save-restoreActivity handles it manuallyRCHDroid
Requires app changes
Risk of state loss or crash
Handles in-flight async tasks
Rebuilds the whole activity
Reported outcome (per abstract)
A qualitative comparison based on the paper's abstract; the paper's main body, including the state-migration and lazy-migration mechanisms and the evaluation setup, was not available for this draft. The 25.46-percent handling-time reduction is the abstract's own reported figure.Underlined values explain themselves when clicked.

Check yourself

Check your understanding

  1. 1. Why can a simple screen rotation lose an Android app's state or crash it?

  2. 2. What is RCHDroid's core idea?

  3. 3. How does RCHDroid handle asynchronous tasks that are still running when the change occurs?

  4. 4. What should a reader keep in mind about this explainer, and what did the paper report?

Sources

The paper is “Transparent Runtime Change Handling for Android Apps” by Zizhan Chen and Zili Shao (The Hong Kong Polytechnic University), published at ASPLOS 2023 (Volume 3), DOI 10.1145/3582016.3582060. The system is named RCHDroid.

This explainer is a draft. The paper’s main text was not accessible at the time of writing (there is no arXiv preprint, no open-access or author copy was located, and the ACM Digital Library PDF returned a bot-verification challenge), so it is written from the paper’s complete abstract together with standard background on the Android activity lifecycle and configuration changes. The abstract supplies the problem and approach: mobile devices often face runtime configuration changes such as screen orientation changes, screen resizing, and language switching; the current Android design adopts a restarting-based solution to load the corresponding resources according to the new configuration, so application developers must explicitly deal with state preservation and restoration brought about by the activity restarting, and otherwise the runtime change will cause state loss and even app crash issues; RCHDroid is a transparent runtime-change handling approach for apps at the Android system level that, when a configuration change occurs, does not restart the activity but instead creates a new activity according to the new configuration and migrates states from the old one to the new one, while putting the old activity into an inactive mode; it proposes a lazy-migration scheme to handle asynchronous tasks that remain working on the old activity, migrating the result events when the asynchronous tasks return; the authors implemented a prototype of RCHDroid with real hardware and released the source code; and overall, using RCHDroid, existing apps can handle runtime configuration changes without any modifications and save the runtime change handling time by 25.46 percent. The explanations of why manual save-restore is error-prone and why asynchronous tasks complicate the change are standard Android background and the natural reading of the abstract, not claims about RCHDroid’s specific internal design. The paper’s exact migration mechanism, the lazy-migration and inactive-mode implementation, the compatibility scope, and the evaluation setup are not reproduced here and should be read from the paper. No numbers beyond the abstract’s have been introduced.

Related papers on Mobile, Edge & Embedded

See all 111 →