Android Profiler
Android (Google)OfficialCreated by Google LLCDistributed by Android (Google)
- Skill
- Tool integration
- Software development
- Apache-2.0
- Low risk
- Has scripts
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The android-profiler skill provides a structured approach to capturing and interpreting Android performance data. It acts as an orchestrator for recording system traces, heap dumps, and CPU profiles, and provides workflows for deep-dive analysis using Perfetto. The skill is designed to help developers identify the root causes of UI jank, memory leaks, battery drain, and system-level performance regressions by leveraging standardized trace analysis and SQL-based querying.
What it does
- Records system traces, CPU call stacks, and memory heap profiles.
- Analyzes Perfetto traces to identify UI jank, frame drops, and startup latency.
- Investigates system-level issues like IPC Binder storms and thread scheduling stalls.
- Diagnoses power-related issues including battery drain and kernel wake locks.
- Debugs memory pressure, LMK events, and native or Java heap leaks.
- Executes custom PerfettoSQL queries for advanced trace data exploration.
When to use it
- When you need to investigate app startup latency or intermittent UI jank.
- When diagnosing memory-related crashes like OOMs or excessive allocation churn.
- When analyzing system-wide performance regressions using A/B trace comparisons.
- When you need to profile power consumption or modem power rail activity.
- When you need to perform ad hoc analysis on complex Android system traces.
Advantages
- Provides a unified workflow for both recording and analyzing performance data.
- Reduces ambiguity by enforcing clear intent disambiguation before execution.
- Includes specialized reference hints for CPU, memory, graphics, and power analysis.
- Supports advanced data exploration via PerfettoSQL integration.
- Ensures consistent environment setup through standardized path management.
Usage examples
- “My app is stuttering during scrolling. Can you help me find the cause?”
- The agent will initiate a trace recording session focused on UI jank, then guide you through analyzing the resulting Perfetto trace for frame drops and thread stalls.
- “I suspect a memory leak in my application. How can I investigate?”
- The agent will help you capture a Java or native heap dump and provide steps to analyze the memory allocation patterns to identify potential leaks.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/android/android-profiler/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip android-profiler.zip -d .agents/skills
Documentation by Google LLC
Your primary role is to figure out what the user wants to do (disambiguation), find the right instructions for it (workflow discovery), and follow them step-by-step (following the execution plan). If the request is unclear, work with the user to finalize the execution plan before proceeding.
Prerequisites and Setup
Before executing any workflows, read references/env_setup.md. It defines
what to set $SKILL_ROOT to - the anchor every other path in this skill is
written against.
Intent Disambiguation
Do not guess the user's intent. If the user request is not clear, ask the user what they want to do before proceeding.
Recording
Route all recording requests through recording/recording_orchestrator. This defines guidelines and pre-flight checks or dependency checks that apply to all recording workflows, and ensures you have the necessary setup to proceed. Read the orchestrator and execute the plan it describes based on what the user wants to record (for example, a system trace or a heap dump).
Analysis
Route all analysis requests through analysis/analysis_orchestrator.
Files
- ATTRIBUTION.mdAdded by AutoGineer965 B
- LICENSELicence file added by AutoGineer11.1 KiB
- SKILL.md2.2 KiB
- analysis/analysis_orchestrator.md1.5 KiB
- analysis/workflows/perfetto-sql/perfetto_sql.md969 B
- analysis/workflows/perfetto-trace-analysis/perfetto_trace_analysis.md4.2 KiB
- analysis/workflows/perfetto-trace-analysis/references/hints/hints_cpu.md2.6 KiB
- analysis/workflows/perfetto-trace-analysis/references/hints/hints_graphics.md2.1 KiB
- analysis/workflows/perfetto-trace-analysis/references/hints/hints_io.md1.8 KiB
- analysis/workflows/perfetto-trace-analysis/references/hints/hints_ipc.md1.7 KiB
- analysis/workflows/perfetto-trace-analysis/references/hints/hints_memory.md2.2 KiB
- analysis/workflows/perfetto-trace-analysis/references/hints/hints_power.md1.2 KiB
- analysis/workflows/perfetto-trace-analysis/references/per_candidate_analysis.md8.8 KiB
- analysis/workflows/perfetto-trace-analysis/references/triage.md3.9 KiB
- recording/recording_orchestrator.md1.5 KiB
- recording/workflows/perfetto-trace-recording/perfetto_trace_recording.md4.7 KiB
- recording/workflows/perfetto-trace-recording/references/example-configs/app_jank.pftxt1.0 KiB
- recording/workflows/perfetto-trace-recording/references/example-configs/cpu_profile.pftxt773 B
- recording/workflows/perfetto-trace-recording/references/example-configs/java_heap_dump.pftxt566 B
- recording/workflows/perfetto-trace-recording/references/example-configs/long_background.pftxt1006 B
- recording/workflows/perfetto-trace-recording/references/example-configs/memory_counters.pftxt1.0 KiB
- recording/workflows/perfetto-trace-recording/references/example-configs/native_heap.pftxt589 B
- recording/workflows/perfetto-trace-recording/references/example-configs/sched_cpu.pftxt836 B
- recording/workflows/perfetto-trace-recording/references/trace_config_reference.md4.9 KiB
- references/env_setup.md513 B
- references/perfetto/bin/trace_processorScript10.8 KiB
- references/perfetto/setup.md1.3 KiB
- references/perfetto/sql.md15.8 KiB
references/perfetto/sql.md
This reference explains how to extract data from a Perfetto trace file
(.pftrace, .perfetto-trace, .pb) using trace_processor and
PerfettoSQL. Read it for ad-hoc querying outside a guided workflow; the
workflows under $SKILL_ROOT/analysis/workflows/ and
$SKILL_ROOT/recording/workflows/ carry their own queries.
The trace_processor binary is what every other Perfetto analysis tool
runs on top of, including the Perfetto UI. Reference docs:
https://perfetto.dev/docs/analysis/trace-processor.
Prerequisite ---
trace_processormust be invokable. Before running any of the shell commands below, read$SKILL_ROOT/references/perfetto/setup.md. It defines how to make the baretrace_processorcommands below work in this environment.
Querying a trace: sessions
Querying goes through a session : load the trace once into a named
background session, then run every query against it with --remote.
Parsing a trace is the expensive part (tens of seconds for a multi-GB
trace); the session pays it once, and every real analysis runs more than
one query.
# 1. Load the trace into a background session --- once per trace.
# Pick a descriptive session name (e.g. derived from the trace file).
trace_processor server unix --name mysession --daemonize TRACE_FILE
# 2. Run queries against the warm session: instant, no reparse.
trace_processor query --remote mysession \
"SELECT ts, dur, name FROM slice WHERE dur > 5e8 LIMIT 5"
# 3. When you are completely done with the trace:
trace_processor server kill mysessionMultiple statements separated by ; are supported in one invocation.
Session rules:
Session names are managed by trace_processor in a per-user session directory --- there are no ports to choose and no collisions with other agents or the Perfetto UI.
Session state persists across
query --remotecalls. ACREATE PERFETTO TABLEorINCLUDE PERFETTO MODULErun in one call is visible in the next, so materializing intermediate results pays off across invocations.Flags that configure trace loading (
--full-sort,--add-sql-package, ...) belong on theserver unixinvocation, not onquery --remote--- the client rejects them with an explanatory error.--remotealso accepts an absolute*.sockpath orhost:port; names are the common case.Forgotten sessions are reaped automatically after 30 minutes idle (
--idle-timeout), but kill your session when the analysis is done.
TRACE_FILE can be a local path, an http(s):// URL, or a Perfetto UI
share link (https://ui.perfetto.dev/#!/?s=<hash>) --- in the last two
cases trace_processor downloads the trace for you (cached under
~/.cache/perfetto/ or the platform equivalent), resolving the share
link to its underlying trace first.
For a single throwaway query on a small trace you can skip the session
(trace_processor query TRACE_FILE "..." parses, queries, and exits),
but treat that as the exception: it re-parses the trace on every
invocation and forgets created tables and included modules between
calls. Default to a session.
Discovering what's in the trace
PerfettoSQL provides a searchable intrinsic table containing every loaded standard-library module, table, view, function, table function, and macro. Use it to verify whether the Standard Library already provides the needed abstraction before drafting custom logic.
Mandatory Schema Check: Do not guess column names or join keys. Always
use a plain LIMIT 0 query to read the exact column schema of any specific
table, view, or query result before drafting your query.
Intrinsic surface --- not stable API. The
__intrinsic_*names below are an implementation detail of trace processor. They're fair game for an agent to use during a session because this reference is loaded, but don't bake__intrinsic_*names into committed scripts, dashboards, or stdlib modules --- they can change without notice.
-- Search every documented stdlib object. Start with one precise phrase or
-- API-like term. In a regexp, `|` means alternatives: prefer
-- `breadth.first|bfs`, not a broad expression such as `breadth|graph|search`.
WITH search(pattern) AS (VALUES ('precise phrase|api_term'))
SELECT o.qualified_name, o.object_type, o.short_description
FROM __intrinsic_stdlib_objects AS o, search AS s
WHERE o.exposed = 1
AND regexp(s.pattern, o.summary, 'i')
ORDER BY regexp(s.pattern, o.qualified_name, 'i') DESC,
o.qualified_name
LIMIT 10;
-- Once a candidate is found, read one human-friendly document containing its
-- identity, description, arguments, return value, and result columns.
SELECT o.summary
FROM __intrinsic_stdlib_objects AS o
WHERE o.qualified_name =
'intervals.overlap.intervals_overlap_count_by_group';
-- Read the runtime schema of any table, view, or query. LIMIT 0 returns the
-- result header with no row scan.
SELECT * FROM slice LIMIT 0;
INCLUDE PERFETTO MODULE slices.with_context;
SELECT * FROM thread_or_process_slice LIMIT 0;
SELECT * FROM (SELECT ts, dur, name FROM slice WHERE dur > 0) LIMIT 0;Useful starting points for any trace:
| View | What's in it |
|---|---|
slice | Atrace slices, async slices, anything with a duration on a track |
thread | One row per thread |
process | One row per process |
thread_state | Scheduling state transitions (Running, Runnable, Sleeping, ...) |
sched_slice | When threads were on-CPU |
counter | Time-series counter samples |
track | Every track in the trace; join on track_id to most other tables |
Static reference for the public surface (does not require a running trace_processor): https://perfetto.dev/docs/analysis/sql-tables.
Using the standard library
Most useful queries are much shorter when you build on stdlib modules instead of joining raw tables yourself. Generated stdlib reference: https://perfetto.dev/docs/analysis/stdlib-docs.
Include a module before referencing the views, tables or macros it defines:
INCLUDE PERFETTO MODULE slices.with_context;
SELECT name, dur, thread_name, process_name
FROM thread_or_process_slice
WHERE dur > 1e9 -- slices longer than 1s
ORDER BY dur DESC
LIMIT 20;A few commonly used modules to know:
slices.with_context--- slice rows joined with their thread / process.sched.with_context---sched_slicejoined with thread / process.android.startup.startups--- one row per app startup.stacks.cpu_profiling--- flat samples and call-graph helpers.android.memory.heap_graph.dominator_tree--- retained-size analysis for Java heap dumps.android.startup.startup_breakdowns--- startup phases (android_startup_opinionated_breakdown).android.frames.timeline--- frames and jank (android_frames).android.anrs--- ANRs (android_anrs).android.binder--- binder transactions (android_binder_txns,android_binder_metrics_by_process).android.memory.lmk--- low-memory kills (android_lmk_events).android.cpu.cluster_type--- big / mid / little CPU clusters (android_cpu_cluster_mapping); pair withlinux.cpu.frequency(cpu_frequency_counters).android.oom_adjuster--- process importance over time: foreground, background, cached (android_oom_adj_intervals).
The module name maps directly to the file path under the stdlib root:
foo.bar lives at foo/bar.sql. Browse the full list at the stdlib
reference linked above.
Tips for writing good PerfettoSQL
Reach for stdlib first. If you find yourself joining
slicetothread_tracktothreadtoprocess, there is almost certainly a stdlib module that already does it. Check the stdlib reference before writing the join.Filter on
dur > 0and Trace Boundaries carefully. Some slices havedur = -1(still open at trace end) and some havedur = 0(instant events). Be explicit about which you mean. When calculating a bounding box (for example,ts + dur) or summing durations (SUM(dur)), handle incomplete durations using:IIF(dur = -1, trace_end() - ts, dur).Robust State Transitions. Avoid manual timestamp arithmetic (for example,
ts + dur = next.ts) to join adjacent events. Rely on standard library modules (for example,sched.runnable,linux.perf.counters,intervals.overlap) which safely handle trace gaps and preemptions.Working with Identifiers:
Use Unique Identifiers for Joins: When writing SQL queries in Perfetto, you must join tables using
utid(unique thread ID) orupid(unique process ID) instead of the regulartidorpid. Why it's useful : The operating system recyclesTIDsandPIDs, whileUTIDsandUPIDsremain unique for the lifetime of the trace, which prevents incorrect joins.Columns like
id,utid,upid,track_idare not stable across traces or even runs of trace_processor on the same trace. You can use them inside a query as join keys, but alongside the IDS, always join out to a stable name (thread.name,process.name,slice.name) when reporting results to the user.Materialise expensive intermediate results.
CREATE PERFETTO TABLE foo AS SELECT ...caches the result so subsequent queries don't redo the work.Note for
SPAN_JOIN: Intermediate tables fed into aSPAN_JOINmust be materialized usingCREATE PERFETTO TABLE, notCREATE VIEW.
Idempotency. Ensure queries are idempotent to prevent "already exists" errors during multiple executions.
For Perfetto objects, always use
CREATE OR REPLACE:CREATE OR REPLACE PERFETTO {TABLE|VIEW|MACRO|FUNCTION}.For SQLite Virtual Tables (such as
SPAN_JOIN),CREATE OR REPLACEis not supported. Explicitly drop them first:DROP TABLE IF EXISTS my_table; CREATE VIRTUAL TABLE my_table USING SPAN_JOIN(...);For standard SQLite indexes, prepend
DROP INDEX IF EXISTS index_name;.
SPAN_JOINsafety.SPAN_JOINwill crash if intervals within the same input table overlap. Always use thePARTITIONED {column}(for example,PARTITIONED track_id) clause to isolate intervals.Avoid
SELECT *in saved queries. Trace processor table schemas can gain columns; pin the columns you actually use.Use
EXPLAIN QUERY PLANif a query is slow. It shows whether SQLite is using indexes. Counter and slice tables have built-in indexes ontsandtrack_id; queries that don't filter on either will scan the whole table.Argument Extraction: Use
EXTRACT_ARG(arg_set_id, 'key')to fetch event properties instead of manually joining theargstable.JSON Parsing: When dealing with JSON text, use standard SQLite JSON functions (for example,
json_extract()) to extract values.String Matching (Avoid
LIKE). UseGLOBorregexp()instead ofLIKE.LIKEcauses performance bottlenecks and treats underscores (_) as wildcards, leading to bugs.Exact matches: Use
=.Substring matches: Use
GLOBwith*(for example,name GLOB '*RenderThread*').Case-insensitive matches: Use
regexp(pattern, input, 'i'). It performs a case-insensitive partial match withoutLOWER()or*wildcards (for example,regexp('renderthread', name, 'i')).
Alias Precision. Always prefix column names with table or view alias, that is:
{alias}.{column_name}.
Common Analysis Patterns
Calculating Time Overlaps & CPU Time:
Primary Method (MANDATORY): Always search the standard library first before writing custom interval logic. For example, to find the exact CPU execution time of a slice, do not calculate it manually; instead, search the docs and use the
slices.cpu_timemodule.Fallback Method (Use ONLY if you have verified no stdlib module or
SPAN_JOINapplies): If you must calculate custom overlap durations between two different sets of time intervals[start1, end1]and[start2, end2]:Condition: The intervals overlap if
start1 < end2andstart2 < end1.Duration: The overlap duration is calculated as `MIN(end1, end2)
MAX(start1, start2)`.
Important: Incomplete Perfetto slices have a duration of -1 (
dur = -1). Always calculate the effective end time usingts + IIF(dur = -1, trace_end() - ts, dur)before applying this logic.
Window Size: When looking for events around a specific timestamp, start with 100ms as the window size.
Total Duration: To calculate the total time spent in slices matching a specific name pattern (for example,
*{name_pattern}*), you must sum their durations. Why it's useful : This helps quantify the total impact of a specific function or feature on performance across multiple calls. Here is an example query (note the safe handling of incomplete slices):sql SELECT count(*) as total_count, sum(IIF(slice.dur = -1, trace_end() - slice.ts, slice.dur)) / 1000000.0 as total_dur_ms FROM slice WHERE slice.name GLOB '*{name_pattern}*';
Analytical Workflow (Standard Operating Procedure)
To ensure accuracy and efficiency, follow these steps:
Research & Dissection: Identify the core question and required data points.
Mandatory Schema Validation: Search
__intrinsic_stdlib_objectsglobally across modules, tables, views, functions, table functions, and macros. Filter toexposed = 1. Use one precise case-insensitive regexp, rank qualified-name matches first, and useLIMIT 10. Once a candidate is found, read itssummary; it contains all argument, column, return, and descriptive metadata.Intent Check: You must verify if a stdlib object already provides the needed abstraction before drafting manual arithmetic or custom joins.
IMPORTANT: For overlaps, intersections, or interval boundaries, search the global object table before writing custom timestamp arithmetic.
Draft & Validate Loop (Max 3 Iterations):
[ ] Draft: Use only verified schemas. Ensure
INCLUDE PERFETTO MODULEis present for non-prelude modules.[ ] Verify Idempotency: Use
CREATE OR REPLACEorDROP TABLE IF EXISTSfor virtual tables.[ ] Check Precision: Are ALL columns prefixed with aliases (e.g.,
s.name)? Are you joining onutid/upid?[ ] String Matching: Did you use
=,GLOB, or case-insensitiveregexp(..., ..., 'i')instead ofLIKE?[ ] Span Join Check: If using
SPAN_JOIN, are tablesPARTITIONEDand materialized?[ ] Execute: Run against the session:
trace_processor query --remote SESSION "QUERY".
Execution Rules:
File Usage: If you must create a SQL file to execute queries (for example, due to query length or escaping issues), you must create them in the
/tmp/directory.Failure Resilience: Debug and fix SQL syntax and logic errors when query fails. Don't simplify the analytical intent to pass validation. For example, if requested to calculate an overlap or intersection, you must fix the intersection math. Don't substitute with disjoint queries (for example, returning independent total durations) as a workaround.
Cleanup & Finalize:
Explicitly return and state the final validated SQL and explain the results to the user.
Save an analysis report. Write a markdown file in the working directory (default
perfetto_analysis_report.md) containing: the question investigated, the trace file(s) analyzed, the findings with concrete numbers, the final validated queries (so the analysis can be re-run), and open questions / next steps. Point the user at it in your final message.Before finishing, delete any temporary SQL files created in
/tmp/.
Where to look for more
Language tour: https://perfetto.dev/docs/analysis/perfetto-sql-getting-started
Trace processor reference: https://perfetto.dev/docs/analysis/trace-processor
Generated table reference: https://perfetto.dev/docs/analysis/sql-tables
Generated stdlib reference: https://perfetto.dev/docs/analysis/stdlib-docs
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
What our scanner noticed· Low risk
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Google LLC
- Publisher
- Android (Google) (Official)
- Distributed by
- Android (Google)
- Source
- android/skills · profilers/android-profiler · commit bf68e2d
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.txt)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Google LLC or Android (Google).
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download android-profiler.zip