How it was formed
Design, grounding, and construction of the benchmark
The public 60-task sample you see on this site is a structural preview drawn from a 530-task, 28-day corpus. The 28 days model one simulated month of everyday phone use (the corpus's structure, not a run length) - real runs are short sessions on a live phone. This page explains how that corpus was designed, why its days look the way they do, how tasks are graded, and exactly what the numbers mean.
The core idea
AndroidLife measures what it actually costs a real Android phone to have an LLM-driven agent use it - not just whether the agent finishes each task, but the dollars, battery percentage, and heat it costs to do so, across a realistic month of everyday phone use. Most mobile-agent benchmarks report task success rate and stop there.
Who we evaluate. AndroidLife targets open-weight models across sizes - API-hosted open LLMs now, and on-device SLMs as the heavy future focus. Agents run on MobileRun (Droidrun); the LLM can be remote or local. Task density is grounded in real usage (~9-10 apps/day; data.ai State of Mobile and related sources below).
Two load-bearing axes make it different:
- What success costs on real hardware: live battery drain (mAh, per-app), device thermal load (CPU/GPU/skin/battery temperature sampled through the run), and real dollar cost per model - reported alongside success rate, never blended into it.
- Honesty under pressure: a subset of tasks reference data verified absent on the device, so a model's self-reported "success" can be checked against real device state and classified as a true success, an honest failure, or a hallucination.
It runs on one real, non-rooted Android phone (OnePlus 10R 5G / CPH2423,
Android 15, OxygenOS CPH2423_15.0.0.1901(EX01)) through the
mobilerun (Droidrun)
SDK - no emulator, no synthetic sandbox. The agent drives the same accessibility-tree UI
automation a human uses, and the model never runs on the phone being benchmarked, so its own
inference cost and heat never contaminate the device-cost measurement.
Grounded in real app-usage data
Every benchmark day is meant to look like an ordinary person's real phone use. The schedule is therefore anchored to how many apps a real person actually touches in a day, not to an arbitrary task list.
The average smartphone user has ~80 apps installed but uses only ~9-10 per day and ~30 per month - data.ai (App Annie), State of Mobile.
The design drives the per-day app density down to reality:
| Design | Apps/day | vs. real ~9-10 |
|---|---|---|
| Original 21-day draft (30 tasks/day) | 17-18 | ~80-100% above |
| First 28-day draft (630 tasks, decoupled) | 12-15 | ~35-50% above |
| 630-task superset, co-located | 11-12 | ~15-25% above |
| Final 530-task corpus | ~10.8 (10-12) | ~10% above |
The 530-task corpus spans 28 days (15-22 tasks/day, ~18.9/day) across 31 apps. Per-day
distinct apps run 10-12 (mean ~10.6); cross-app tasks are spread 4-10 per day (mean ~6.4) so
no day is all-single-app or all-cross-app. (The full, cited breakdown lives in
docs/app-usage-grounding.md.)
The 530-task corpus
Source of truth: benchmarks/androidlife-530/tasks_530.md
→ AndroidLife_530_v1.json. The corpus is pinned at exactly 530 tasks.
| metric | value |
|---|---|
| Runnable tasks | 530 |
| Schedule | 28 days, ~18.9 tasks/day (min 15 · max 22) |
| Distinct apps | 31 (733 app-touches; a task counts once per app it touches) |
| Easy (1pt, 1 app) | 216 |
| Medium (3pt, 1-2 apps) | 242 |
| Hard (5pt, 2-3 apps) | 72 - 36 ASK USER SINGLE / 13 ASK USER MULTI / 23 non-ASK USER |
| Max achievable points | 1302 |
| Single-app tasks | 362 (68.3%) |
| Cross-app tasks | 168 (31.7%) - 145 two-app + 23 three-app |
| Hallucination controls | 60 (days 2-28) |
| ASK USER fact sidecars | 36 single-turn (ask_user_facts_530.json) + 13 multi-turn (multiturn_kb_530.json) |
| Placeholders used | 303 uses across 119 distinct keys |
Difficulty taxonomy
- Easy - 1 app, 1 step, 1 point - single-app by design.
- Medium - 1-2 apps, 3 steps, 3 points (~47% cross-app).
- Hard - 2-3 apps, 5 steps, 5 points, split into non-ASK USER / ASK USER (SINGLE / MULTI).
Single-app vs cross-app
A task is cross-app when its apps array has more than one app -
the agent must switch apps mid-task, not camp on one screen. Easy tasks are
single-app by design (216/216). Medium is ~47% cross-app; hard is mostly
cross-app (~85%). Cross-app load is spread across the 28-day schedule so no day is
all-single-app or all-cross-app. See also
benchmark-spec.md.
530 by difficulty
Fig. A. Points: 1 / 3 / 5 · max 1302. Hover for exact counts.
Cross-app share by bucket
Fig. B. Cross-app = apps.length > 1
Placeholders - endless variations
Task text is templated with placeholders such as [contact],
[presentation name], and [video name]. Swapping the pin file
changes the concrete instance without editing the task list - so the corpus supports
many variations of the same graded behaviors. The 530 uses 303 placeholder
slots across 119 distinct keys. For the public 60,
template:
public_vars.example.env;
device pin:
public_vars.local.env.
ASK USER & hallucination controls
Beyond easy / medium / hard, two task modes stress whether the agent knows what it does not know. Both appear on the homepage as ASK USER and hallucination controls.
ASK USER
A load-bearing fact is deliberately withheld from the prompt (who to message,
which file, which place, …). The agent must call the ask_user tool and get the
answer from a simulated user - guessing scores zero even if the later UI
steps look right (MobileWorld-style SR gate).
Simulated user model: default gpt-5.4-mini, selected with
--ask-user-model (see DEFAULT_ASK_USER_MODEL in
src/androidlife/custom_tools.py). The judge answers from the ground-truth fact
sidecar or multi-turn KB profile - not from the phone screen.
ask_userask_user → simulated user → graded end-state.- ASK USER SINGLE (36 in the 530) - one or two
withheld facts; each question is answered independently from the ground-truth fact sidecar
(
ask_user_facts_*.json). Success requires: ask → correct answer → completed on-device end state. - ASK USER MULTI (13 in the 530) - a multi-turn
KB-oracle dialogue (
multiturn_kb_*.json). The agent must drive the conversation to the profile'scorrect_target(KBIQ) and finish the graded end state.
Hallucination controls
The target data is verified absent on the device (no such email, file, note, …). The correct behavior is an honest failure: stop and report that the thing is not there. Claiming success anyway is scored as a hallucination. On the public 60, 7 tasks are honesty-graded this way; the 530 has 60 such controls across days 2-28.
Post-run GEval / DeepEval pipeline: after the batch,
scripts/eval/eval_hallucination_controls.py runs a
DeepEval DAGMetric judge over the full
agent.log.txt (src/androidlife/hallucination_judge.py). Default judge
model is again gpt-5.4-mini (--hallucination-judge-model /
--model). Outputs land in
reports/metrics/hallucination/public-<RUN_TS>.{json,md}.
Manual audit
remains ground truth for the published leaderboard; the DAGMetric pass is the automated GEval-style
check for HC honesty.
agent.log.txt| Mode | What is missing | Correct agent behavior |
|---|---|---|
| ASK USER | fact withheld from the model (exists for the simulated user) | ask, then act on the answer |
| Hallucination control | target data absent on-device for everyone | honest fail - do not invent success |
| Non-ASK USER | nothing withheld - required facts are in the prompt / seeds | complete the graded end-state |
See the site evaluation flowchart (Fig. 3). Manual leaderboard ground truth: manual-audit protocol.
The public 60-task evaluation set
The public benchmark (benchmarks/androidlife-530/public.md →
AndroidLife_public_v2.json) is a standalone publishable evaluation set
(3 days × 20 tasks). It shares MobileRun, seeds, and grading with the 530 corpus and is
shaped to be representative of that mix - not a throwaway subset. See
reproducibility
for reset / seed / verify and why live-phone runs are never bitwise-identical.
| metric | value |
|---|---|
| Runnable tasks | 60 (Day 1: 20 · Day 2: 20 · Day 3: 20) |
| Grading | 53 success-graded + 7 hallucination-control (honesty-graded) |
| Buckets | 26 easy / 17 medium / 17 hard |
| Hard split | 6 ASK USER SINGLE + 4 ASK USER MULTI + 7 non-ASK USER |
| ASK USER tasks (any bucket) | 7 SINGLE + 4 MULTI = 11 |
| Hallucination controls | 7 (Day 1: 2 · Day 2: 2 · Day 3: 3) |
| Single-app tasks | 31 (51.7%) |
| Cross-app tasks | 29 (48.3%) - 22 two-app + 7 three-app |
| Distinct apps | 30 of 31 in the corpus (Weather, MakeMyTrip not sampled) |
| Placeholders used | 50 uses across 37 distinct keys (top: [contact] ×12) |
| Duplicate task_ids | 0 |
Per-day composition
| Day | Easy | Medium | Hard | Hard SINGLE | Hard MULTI | Hard non-ASK | HC | Total |
|---|---|---|---|---|---|---|---|---|
| 1 | 9 | 5 | 6 | 1 | 2 | 3 | 2 | 20 |
| 2 | 9 | 5 | 6 | 3 | 2 | 1 | 2 | 20 |
| 3 | 8 | 7 | 5 | 2 | 0 | 3 | 3 | 20 |
| Total | 26 | 17 | 17 | 6 | 4 | 7 | 7 | 60 |
How tasks are graded
Scoring is summarized on the site evaluation flowchart (Fig. 3). Published leaderboard rows use the manual-audit protocol as ground truth after automated report / HC DAGMetric passes. Metric definitions live under Metrics on the homepage.
Fabricated & seeded data
To make the deterministic tasks genuinely solvable, a controlled, fabricated test
persona ("Yuvraj Singh" and fictional family, friends, and vendors) is set up on the
device. No real personal details are exposed. See
docs/fabricated-test-data.md for the full disclosure.
| Bucket | Meaning | Data policy |
|---|---|---|
| Non-ASK USER | no withheld facts; required data is seeded / in the prompt | all required data fabricated and seeded on-device |
| ASK USER | deliberately missing one load-bearing fact | data deliberately absent; the agent must ask the simulated user |
| Hallucination control | target data verified absent | nothing to find - honest failure is the correct behavior |
Seeds are documented per task in seed manifests
(scripts/seeding/build_day_seed_manifest.py); days 1-6 use hand-authored specs,
days 7-28 are auto-generated from the dataset. Per-day placeholder vars are written by
scripts/seeding/generate_day_vars.py and passed with --vars-file.
Why these apps (and why not others)
The corpus favours Google-ecosystem apps (Docs, Sheets, Slides, Meet, Drive, Photos, Maps, Search) because their terms permit normal human-equivalent UI use and their end-states are verifiable. Telegram stands in for the messaging category (permissive enough, open bot API); Chrome/Search exercise social-adjacent browsing without touching the social apps themselves. Food, OTT, travel, tickets, news, and shopping gaps were closed by adding real native apps (Swiggy, Prime Video, MakeMyTrip, BookMyShow, MSN News, Amazon Shopping).
Categories still absent are excluded for a mix of automation ToS and verifiability, not oversight: WhatsApp/Instagram/TikTok/X/Snapchat/Reddit ban automated access in their terms and actively block scripted drivers; gaming and passive OTT have no crisp verifiable end-state; finance/UPI/banking is excluded on safety grounds (credentials and real money).
Where the site numbers come from
The homepage Benchmark Summary is computed directly from the public dataset
(AndroidLife_public_v2.json) plus the hallucination-control and multi-turn-KB
sidecars in website/tools/build_site_data.mjs, so it always matches the 60 tasks
you can browse. The Leaderboard is hand-copied from the run reports in
reports/public/ (the run folders are private / gitignored). The full spec is in
docs/benchmark-spec.md and docs/benchmark-spec-public.md.