Android screenrecord stuff
Last updated: 2015-10-12

Android 4.4 ("KitKat", API 19) introduced the screenrecord shell command. This allows a developer to record the device's screen as a .mp4 video file (example).

An updated version, v1.1, was made available as source in AOSP on 11-Dec-2013, but was not shipped in an OS update. Version 1.2 was shipped with the next release, Android 5.0 ("Lollipop").

The features provided by screenrecord are now better provided by the MediaProjection API, which allows ordinary, unprivileged applications to record the screen. screenrecord may still be of some use for bug reports and analysis on development devices, and unlike store-bought recording apps its presence can be assumed.

What's new in v1.2

The combination of these two features means you can "mirror" the device display on your desktop by feeding the output of the screenrecord command into a video player on Linux.

What's new in v1.1

The "info" page added by --bugreport shows the current date and time, and dumps a collection of system properties, notably ro.build.description. This makes it easy to tell which device the recording was made on, what release of the software, and when it was captured. The per-frame timestamp is (mostly) consistent with logcat, which should make it easier to match logs with recorded video. A frame counter is also displayed for easy reference in bug reports.

The --bugreport mode does add an additional composition step, increasing the overhead of recording the screen. Depending on the circumstances and device capabilities, this may cause a noticeable slowdown.

Quirks and limitations

We've heard a few complaints and feature requests:
• You have to run it as the shell user, or via "su" on a rooted device.
This is intentional. It should not be possible for one app to make a recording of another app, since that could be used for identity theft or other sorts of spying.
• There's no API to allow an application to record itself.
This may be addressed in the future. For some applications (e.g. pure GLES) this is reasonably straightforward now. For others, you would need to create a virtual display through the Presentation API and record through that (see e.g. the notes in the last paragraph of the answer to this question).
• Sound is not recorded.
This may be addressed in the future.
• Device orientation changes are not tracked (v1.0) or handled poorly (v1.1).
This may be addressed in the future.
• Doesn't work on the AOSP emulator.
This is a known problem, caused by limitations in the software AVC codec used by the emulator. This may be addressed in the future.
• On some devices, screenrecord doesn't record at the full resolution of the display (e.g. Nexus 7 (2013)).
This is a limitation of the video encoder, not screenrecord. The screenrecord command has no way of determining what the valid resolutions are for a given device, so it tries to record full screen, and if that fails it drops back to 720p (1280x720 or 720x1280).
• Hitting Ctrl-C to stop makes it difficult to automate. Also, there's no feedback when the command has finished saving the movie to disk.
This is a bit awkward to fix because adb doesn't send stdin to the device, so you can't write an interactive command (plain shells get special treatment). There are ways to make this better, though, which may be implemented in the future.
• The device isn't as smooth when screenrecord is running.
This is a consequence of the additional work screenrecord is doing. Devices that are more powerful (and/or doing less work when drawing the screen) are affected less. It may be possible to improve this in the future.

How it works

The screenrecord command is a 100% native shell-interface program. It interacts with the graphics compositor (SurfaceFlinger) and media encoder (mediaserver) through IPC requests. It uses a broad selection of APIs that are not public, and is therefore a terrible example of how to write code for Android. (There are public equivalents of everything used by screenrecord in the Android app framework, they're just not accessible from purely-native code. They also require special permissions.)

screenrecord uses a mirrored virtual display to capture the frames composited by SurfaceFlinger. When the screen is updated, screenrecord gets a frame; when nothing changes, no frames are received. Gaps in time are "recorded" by advancing the presentation time stamp in the video file, not by repeating frames. These time stamps are provided by SurfaceFlinger using the system monotonic clock, and reflect the time when the frame was composed.

Changes to the realtime clock (a/k/a "wall clock") time won't affect the timing of video frames, but will alter the time shown in logcat messages. The timestamps shown in the --bugreport overlay are based off the monotonic clock, so updates to the realtime clock will skew the times in the video away from the times in logcat output. This is not expected to be a significant problem. Note also there can be a couple frames of latency between the time something happens and the time it appears on screen.

In normal operation, frames from SurfaceFlinger are sent to the video encoder, which delivers encoded data to screenrecord (i.e. SurfaceFlinger -> encoder -> screenrecord). With the frame timestamp display enabled for --bugreport mode, the path is SurfaceFlinger -> screenrecord -> render (frame + timestamp) -> encoder -> screenrecord. The extra render step -- a full-screen blit plus a few textured triangles -- taxes the GPU more heavily.

What's in the --bugreport overlay?

The "info" page shows the screenrecord version and a full timestamp, followed by a dump of interesting system properties (normally accessible with adb shell getprop <property-name>). The last item is OpenGL driver info, obtained with glGetString().

Incidentally, rendering of the "info" page doesn't delay the start of frame capture. The frame is simply drawn with a timestamp set a quarter-second in the past.

Each recorded frame of video has an HH:MM:SS.mmm timestamp, followed by a frame counter. The number in parenthesis is the number of frames that were rendered to the virtual display but dropped by screenrecord; unless your device is heavily loaded, this should always be zero.

What's wrong with screen rotation?

Screen rotation requires a restart of the foreground activity. While that's going on the activity can't redraw the screen, so the system does a bit of visual trickery: it grabs a screen shot and displays that instead.

The trouble is that the screen shot is displayed in a post-rotation configuration, while the app is still drawing in a pre-rotation configuration. Normally all interested parties (the window manager and SurfaceFlinger) are in sync, so all you see is the screen shot, which is rendered on top. Unfortunately, screenrecord is a bit late getting the memo, and continues to capture what the app is drawing -- but now it's partially overlaid by the rotated screen shot.

It's possible to do this right, but it's a bit of an effort to do it in screenrecord.

Ideally the rotation would also resize the encoded video mid-stream to avoid the letterbox/pillarbox effects.

Further Assistance

Bugs and feature requests should be reported on the AOSP bug tracker.