Capturing Nougat Screenshots Using adb shell
Prior to Android Nougat, I used the following bash function to speedily save screenshots to my local machine:
However, executing this function when using a device running Android Nougat results in a corrupted output file. What gives?
Background
The output of the adb shell’s screencap utility is known to be somewhat funky on older (read: pre-Nougat) versions of Android. In particular, “adb shell” performs an automatic line feed (LF) to {carriage return (CR) + line feed (LF)} conversion. This can be observed by capturing a “naive” screenshot (no perl sanitization):
and then inspecting the corresponding hex dump:
All valid PNG files start with the following 8-byte header:
But look at the first 10 bytes of our “naively”-captured pre-Nougat screenshot:
They don’t match! Each occurrence of the byte “0a” in the correct byte sequence has been replaced with a pair of bytes, “0d” “0a” in the incorrect byte sequencing. This is precisely the line feed (LF) to {carriage return (CR) + line feed (LF)} conversion mentioned earlier. The global perl search-and-replace in the original script reverts this heavy-handed manipulation and results in a valid PNG file.
Nougat
Here’s the hex dump of a “naively”-captured Nougat screenshot:
The first 8 bytes do match the expected PNG file header, so we can deduce that “adb shell” has not performed the line feed (LF) to {carriage return (CR) + line feed (LF)} conversion in this case! This also explains why my original bash function always produces invalid Nougat screenshots. By attempting to undo a conversion that was never applied, the perl search-and-replace mutilates the PNG file header, replacing the required “0d” “0a” sequence with a single “0a”.
Solution
For now, I’ve defined separate pre-Nougat and post-Nougat screenshot bash functions to deal with this change in behavior:
There’s probably a slick way to unify these functions by inspecting the incoming bytes and conditionally applying the global perl search-and-replace, but the solutions above work well enough for me.