Repository: flutter
Issue: Support passing VM flags during background execution
Labels: platform-android,engine,c: proposal,P2,team-android,triaged-android

### Problem

VM Flags determine whether the isolates start paused (for debugging), whether we use software or hardware rendering (for Scuba) and many more. When a VM is started and configured with a set of flags, it cannot be changed.

For Android, Flutter tooling sets these flags via adb. When adb constructs the Intent to launch Flutter activity, it puts these as Intent extras. The extras are then received and processed by the Flutter activity. They are eventually passed to `ensureInitializationComplete` call.

This creates a problem for background execution because the event that causes the VM to start does not get initiated via the process outlined above (no flutter tools, no activity, no intents). Every call to ensureInitializationComplete when the isolate needs to be started in the background receives null as part of VM args, which is far from ideal. If we intend to support background execution on Android, we need to make these flags available to the VM everywhere.

### Proposals
We will examine several proposals to expose the flags outside the activity.

#### Manifest
Anything that gets put into the AndroidManifest is immediately available to the application. Android embedding itself makes use of manifest values when loading resources. We could put the list of flags in the manifest for the application to read.

Pros:
- Well understood and reliable way of reading configuration on Android.
- Hard to tamper since manifest becomes part of a signed APK
- This is an important pro compared to the current status. Any application can generate intents with an arbitrary set of extras. If we make the flags only accessible via manifest, we protect against this.
- There’s a canonical way to merge manifests
- Apps don’t need to change their manifests. We can output a manifest file with only VM flags and leave it to Android tooling to merge it to final App manifest.

Cons:
- Need to change how tooling works today. Intent extras can be constructed at runtime. Manifests need to be built at compile time.
- Might be easier to leak into production apps. E.g. if someone manually edits their manifest to set flags and then forgets them.
- We will end up with confusing flags. For instance, tooling supports --use_prebuilt_application. However, that won’t work with any of the other flags since manifest cannot be retroactively included in a prebuilt APK.

#### Configuration File via ADB
We can put the configuration in a file and copy it to the device using adb. ResourceManager can be used to read it back.

Pros:
- Can be done at runtime. We can change this file without having to recompile the whole app.
- Since the application is not modified, it would be difficult to leak this to release.

Cons:
- Additional complexity to find and read this file. This isn’t too bad since we already read back files in ResourceManager when engine starts.
- We have an extra adb step before starting the app. Copying a file using adb push to an application specific folder might not be possible. We can hack it by copying it to /tmp/<package_id>.cfg
- Security concerns. The app will be looking for a file on disk to load as configuration. We should make sure a malicious third party cannot place a set of instructions there.

#### Configuration File via Assets
A variation of the proposal above is to include the configuration file in the APK. This is very much like a manifest so it carries most of the pros and cons of that approach with a few differences:

- Additional complexity to find and read this file whereas manifest APIs are well defined.
- Harder to leak into production than manifest.

#### Keep Using Intents
Intents work fairly well for the runtime configuration case. This would require us to minimize the cases where the single isolate is instantiated from a place where no intent is available.

If we don’t start the isolate eagerly and the Flutter activity starts it, you get the proper flags. This fixes the broken development and testing flows since those never start via a background event.
 
- We could only invoke the isolate with null params iff the application was started due to background processing.
   - There’s no way to detect this since… there’s no intent.
- We could only invoke the isolate with null params iff we detect (from a plugin) that the isolate is not running.
   - This would allow apps to start from tooling or IDE normally.
   - However, if we want them to start due to a background activity, we would have to forego debugging.
   - All background plugins need to handle this.
   - Might make sense if we expose an API for plugins “to request an isolate”.

With this approach, we lose the ability to debug background isolate. Therefore, in addition to delaying the isolate start, we can save flag values to persistent storage the first time the application starts.
- This effectively creates a configuration file from within the app.
- Enable debugging of truly background isolates via this method:
   - Start the app
   - Kill the app
   - Invoke the background event
- Upgrades might become a problem where the configuration is not wiped.
- Starting the app overwrites the args so the sequence above still works.
- It writes a file the first time the app starts but during development so it should fine.

This feels like a band-aid fix because it does not make flags available everywhere. We might find other use cases in the future (such as starting isolate from a service) that might not be covered by this approach.

### Detailed Solution
Currently I am leaning towards two solutions:

[short term] “Keep using Intents” solution solves most of the use cases w.r.t. debugging and tests while avoiding a major change in the tooling. We will implement this as a layer above the Android embedding only in google3.

[long term] “The Manifest” solution is a secure, well understood and well supported way of defining configuration. In the long term, we also need to solve the pre-warmed isolates use case. At that point, the google3 methodology will be deprecated and migrated to using manifests.