# Android SDK

> How Elide finds or provisions the Android SDK, installs its components under accepted licenses, pins their revisions, and reports them.

The Android SDK is not bundled with Elide: it carries its own licenses. Elide uses an SDK that is already installed,
or provisions one of its own, and resolves which of its components to use for the API level being built.

## Where the SDK comes from

The first of these that applies is the SDK root:

| Source | Root |
| --- | --- |
| `android.sdk` in `elide.pkl` | A path, `"managed"` or `"system"`. |
| `ANDROID_HOME` | The directory it names. |
| `ANDROID_SDK_ROOT` | The directory it names. |
| Android Studio's location | `~/Library/Android/sdk` (macOS), `~/Android/Sdk` (Linux), `%LOCALAPPDATA%\Android\Sdk` (Windows). |
| Managed SDK | `~/.elide/toolchains/android`. |

```pkl
android {
  namespace = "com.example.app"
  compileSdk = 36
  sdk = "managed"
}
```

| `android.sdk` | Means |
| --- | --- |
| absent | The environment, then Android Studio's location, then the managed SDK. |
| `"managed"` | The managed SDK, whatever the environment holds. |
| `"system"` | An installed SDK only. Nothing is ever downloaded; what is missing is reported. |
| a path | That directory. |

An SDK found through the environment or Android Studio's location is never modified unless you ask, with
`elide install` or `--install-sdk`.

The managed SDK starts from the Android command-line tools release this Elide pins, verified by SHA-256. Its own
`sdkmanager` then installs every other component, in the layout Android Studio uses, so Studio can be pointed at
it.

## Install components

A plain `elide build` installs nothing. When a component is missing it fails, naming what to install:

```text
Android SDK is missing: …/build-tools/36.0.0/aapt2
Install with: sdkmanager --install 'build-tools;36.0.0'
Or run elide install, or pass --install-sdk, to install them
```

| Command | Installs |
| --- | --- |
| `elide install` | The platform and build-tools the build needs, and every component the lockfile records. |
| `elide build --install-sdk` | What the build is missing. |
| `elide build android-emulator --install-sdk` | The emulator and its system image too. |
| `elide run`, `elide test --device` | On a terminal, what the run is missing, after asking. |

`elide install && elide build` is a complete CI recipe. In CI, add the license acceptance:

```bash
elide install --accept-android-licenses
elide build
```

## Licenses

No component is installed under a license that has not been accepted.

- `sdkmanager` records an acceptance under `<root>/licenses`; a root that has one is not asked again.
- On a terminal, `elide install` asks once before downloading.
- Off a terminal, `--accept-android-licenses` or `ELIDE_ANDROID_ACCEPT_LICENSES=1` is the acceptance.
  `--install-sdk` on a build is also an acceptance, for what that build installs.
- With none of these, the install fails and prints the command:

```text
The Android SDK licenses have not been accepted, so nothing was installed
Accept them with: elide install --accept-android-licenses (or set ELIDE_ANDROID_ACCEPT_LICENSES=1)
```

`sdkmanager` is never answered on your behalf: a component under a license it has not recorded fails to install.

## Which components a build uses

Components are resolved against the installed SDK, not derived from `compileSdk` alone:

| Component | Resolved as |
| --- | --- |
| Platform | `platforms/android-<compileSdk>`, else the newest `android-<compileSdk>.<revision>` |
| Build-tools | `android.buildTools`, else the newest installed release for `compileSdk`, else the newest newer one |
| System image | `android.device.systemImage`, else an installed image for the device's `api` on the host ABI |

Platform-tools, the emulator and system images are needed only to run on a device, and are checked by the tasks
that use them.

```pkl
android {
  namespace = "com.example.app"
  compileSdk = 36
  buildTools = "36.0.0"
}
```

## Lockfile

The project lockfile (`.dev/elide.lock.v2.bin`) records what a build resolved:

- the kind of root (`system` or `managed`; not its path, which differs between machines);
- the revision of `cmdline-tools`, `platform-tools`, `emulator`, each `platforms;…`, `build-tools;…` and
  `system-images;…` package;
- the R8 and bundletool releases.

While `compileSdk`, `buildTools`, the devices' API levels and system images and the kind of root are unchanged, a
build uses the recorded platform and build-tools and boots the recorded system image even when a newer one is
installed, and `elide install` installs exactly the recorded packages. A component installed at another revision
than recorded is reported as a warning. Commit the lockfile so every machine builds against the same components.

```bash
elide install --update   # re-resolve against the installed SDK and record the result
```

R8 and bundletool are not part of the Android SDK. Each Elide release pins one of each, downloads it once and
verifies it by SHA-256.

## Inspect the SDK

```bash
elide project info
```

In a project declaring `android`, the output has an Android section:

| Field | Shows |
| --- | --- |
| Root, source | The SDK root and where it came from. |
| Platform, build-tools | Each with its installed revision. |
| Platform-tools, emulator, cmdline-tools | Installed revisions. |
| System images | Each image the devices use, with its revision. |
| Missing | What the manifest needs that is not installed. |
| Devices, emulators | Attached devices, and running emulators with their AVD. |

The `android/sdk` tool of `elide mcp` returns the same report to an agent ([Editors and agents](https://elide.help/docs/toolchain/android/editors#agents)).

## Environment variables

| Variable | Effect |
| --- | --- |
| `ANDROID_HOME`, `ANDROID_SDK_ROOT` | The SDK root, when `android.sdk` is absent. |
| `ELIDE_ANDROID_ACCEPT_LICENSES=1` | Accepts the SDK licenses off a terminal. |
| `ANDROID_USER_HOME` | The directory holding `debug.keystore`, as for Android's own tools; `~/.android` when unset. |
| `ADB_EMU` | Passed to the `adb` server Elide starts; `0` unless set ([Headless hosts](https://elide.help/docs/toolchain/android/run#headless-hosts-ci-and-wsl)). |
