N07 — Custom boot animation
Replace the boot animation: build a bootanimation.zip with a valid desc.txt, install it, and learn the format's rules about frame counts, part directories and loop counts. The most visible platform change per line of effort.
The boot animation is the cheapest platform change that produces something you can see. It is also a
genuinely instructive one: the format is old, simple, and unforgiving in specific ways, and the player
is a normal service started by init. Everything you need is in the platform source.
Hardware note: a full build is optional here. You can push a bootanimation.zip to an existing
userdebug build and reboot, which makes this the lightest of the seven nerd projects — though
building the image is the only way to bake the change in.
TL;DR#
- The animation is a ZIP named
bootanimation.zipcontainingdesc.txtandpartN/folders of PNG frames. - The player searches
/system/media/bootanimation.zipfirst, then/oem/media/bootanimation.zip. Both paths come from the format documentation in the platform source. desc.txtstarts withWIDTH HEIGHT FPS [PROGRESS], then one line per part.- A part line is
TYPE COUNT PAUSE PATH [options], wherepplays unless boot finishes first. - The ZIP is stored, not compressed. The format documentation says so explicitly.
What you are building#
A three-second animation: two parts, one that plays while the system is still booting and can be cut
off when boot finishes, and one marked to play to completion. Small frames, a low frame rate, and a
desc.txt that matches the frame counts exactly.
The format#
The format is documented in FORMAT.md, next to the player in frameworks/base/cmds/bootanimation/.
bootanimation.zip
├── desc.txt
├── part0/
│ ├── 000.png
│ └── 001.png
└── part1/
├── 000.png
└── 001.pngdesc.txt's first line is WIDTH HEIGHT FPS [PROGRESS]. The optional fourth value shows a
percentage on the final part. Every following line describes a part:
TYPE COUNT PAUSE PATH [FADE [#RGBHEX [CLOCK1 [CLOCK2]]]]| Field | Meaning |
|---|---|
p | Plays unless interrupted by the end of boot. |
c | Plays to completion, no matter what. |
f | Like p, but fades out a specified number of frames. |
COUNT | Repetitions. 0 loops until boot finishes. |
PAUSE | Delay in frames after the part. |
PATH | The part directory. |
#RGBHEX | Optional background colour. |
The TYPE letters and their meanings are quoted from FORMAT.md in the platform source; the
p/c/f distinction is the part people get wrong, because it determines whether the animation is
cut off when boot completes.
Steps#
- Prepare the frames
Export frames at the size you intend to declare, and name them with zero-padded numbers so lexicographic order matches playback order. The format uses PNG frames in a directory; do not use another image format because it happens to open on your desktop.
You should seePNG files numbered so they sort correctly. - Write desc.txt
An illustrative two-part animation:
720 1280 30 p 1 0 part0 c 1 0 part1Read it as: 720 by 1280 at 30 fps;
part0plays once and can be interrupted by boot completing;part1plays once more and is not interrupted. The numbers are invented for the example — use your own frame size and rate. If you want the first part to keep looping while boot continues, give it aCOUNTof0.You should seeA file with one size line and one line per part. - Match the frame counts
COUNTis a number of repetitions of the whole part, andPAUSEis a delay measured in frames, not seconds or milliseconds. A 30 fps animation withPAUSE 30holds the last frame for one second. The most common authoring mistake is treatingPAUSEas milliseconds.You should seeCOUNT, PAUSE and the directory contents agree. - Zip it without compression
The format documentation is explicit that the archive is not actually compressed. Create a ZIP with no compression, and make
desc.txtand thepartNdirectories the top level of the archive — not nested inside a folder. A ZIP made by right-clicking a folder usually nests, and the player then finds nodesc.txt.You should seeA stored ZIP with a top-level desc.txt. - Install it on a running device
Push the ZIP to
/system/media/and reboot. The commands are in the terminal block below. This requires a writable system partition, so it works on a userdebug or eng build; on a production device the path is closed and the animation must come from the image.You should seeThe next boot shows the animation. - Or bake it into the build
Copy the ZIP into the product's system image with the product configuration, then build and boot the target. Adding a file to the image is a product configuration change; the exact variable and file layout depend on your product, so follow the AOSP build documentation for copying files into the image rather than inventing a rule.2
You should seeThe file is in the system image after a build. - Confirm the player ran
The player is the
bootanimservice, declared inframeworks/base/cmds/bootanimation/bootanim.rcasservice bootanim /system/bin/bootanimationwithclass core animation,user graphics,group graphics audio,disabledandoneshot.1 The log check is in the terminal block below. If logcat shows nothing, the service was not started at all and the problem is not your ZIP.You should seeBoot animation log lines, and the animation on screen.
Install and check#
adb root
adb remount
adb push bootanimation.zip /system/media/bootanimation.zip
adb reboot
adb logcat -b all | grep -i bootanimExample output
Illustrative — no device was used in this run.adb root and adb remount require a userdebug or eng build. On a production device the system
partition is not writable and the animation has to come from the image instead.
The files you touched#
- FORMAT.mdthe authoritative description of desc.txt and the ZIP layout
- bootanim.rcthe init service definition for the player
- BootAnimation.cppthe player itself, if you want to know why a file was rejected
- bootanimation_main.cppthe entry point the service execs
Verification#
Two independent checks. The log tells you the player looked for the file and played it; the screen tells you the frames were what you expected. If the screen stays black and the log shows the player running, the ZIP is wrong. If there is no log at all, the service did not start and the ZIP is irrelevant.
What can go wrong#
- The ZIP is nested in a folder.
desc.txtmust be at the top level of the archive, not insidebootanimation/. This is the single most common failure. - The ZIP is deflated. The format documentation says the archive is not compressed. A compressed ZIP may be rejected outright.
desc.txtnames a part that does not exist, or names a directory with no PNGs. The player has nothing to draw.- The size line does not match the frames. Frames at a different resolution than the declared size look stretched or cropped.
PAUSEis treated as milliseconds. It is a frame count, so the hold time depends on the declared fps.- The animation ends abruptly. The first part is
p, which is interrupted when boot completes. If you want to see all of it, usec. adb remountfails. The build is not userdebug, or the partition layout does not allow a remount. Use the image-build route instead.- The screen stays black on a user build. On some builds the boot animation is suppressed in favour of a boot logo or a different splash mechanism, which is a different component entirely.
Sources#
Sources
Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.
- sourceAndroid Code Search (cs.android.com)cs.android.comaccessed 2026-10-27↩
- docsBuild Androidsource.android.comaccessed 2026-10-27↩