Nexus and Pixel Devices Migrate to SDCardFS in Android O

We may earn a commission for purchases made using our links.

With every new release of Android comes many exciting features. Android O will bring notification channels, Autofill Framework for password managers, Picture-in-Picture mode for phones, adaptive icons, and more. The features that I’ve listed are only a few of the changes introduced in Android O, but there are many features that Google chooses not to publicize, some subtle and some not so subtle, that nonetheless are welcome additions to the Google Android experience. Although you are likely to eventually come across some of the more subtle feature additions to the Android software, you as an end user probably don’t know about many of the changes made under-the-hood, such as to the kernel. After some digging around in the Android O Developer Preview, we discovered that SDCardFS, the in-kernel FUSE replacement to emulate FAT-on-sdcard style directory permissions, is now in use.

If you are thinking to yourself “what is FUSE? Why is Google replacing FUSE with SDCardFS? What is SDCardFS?” then I recommend that you read through my previous article that answers these questions in great depth. For a brief summary of the benefits of SDCardFS, essentially the move should significantly reduce I/O overhead on operations performed on the external storage, eliminate double caching of page cache, and eliminate odd PC file transfer errors such as incorrect time-stamps being shown on your photos.

We discovered this change by comparing the output of a mount command on a Google Pixel (sailfish) running Android 7.1.2 Nougat and the first Android O Developer Preview.

Output of mount command on Android 7.1.2 Nougat rootfs on / type rootfs (ro,seclabel) tmpfs on /dev type tmpfs (rw,seclabel,nosuid,relatime,size=1902076k,nr_inodes=475519,mode=755) devpts on /dev/pts type devpts (rw,seclabel,relatime,mode=600) proc on /proc type proc (rw,relatime,gid=3009,hidepid=2) sysfs on /sys type sysfs (rw,seclabel,relatime) selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime) debugfs on /sys/kernel/debug type debugfs (rw,seclabel,relatime) none on /acct type cgroup (rw,relatime,cpuacct) none on /dev/stune type cgroup (rw,relatime,schedtune) tmpfs on /mnt type tmpfs (rw,seclabel,relatime,size=1902076k,nr_inodes=475519,mode=755,gid=1000) none on /config type configfs (rw,relatime) none on /dev/cpuctl type cgroup (rw,relatime,cpu) none on /dev/cpuset type cgroup (rw,relatime,cpuset,noprefix,release_agent=/sbin/cpuset_release_agent) pstore on /sys/fs/pstore type pstore (rw,seclabel,relatime) /dev/block/bootdevice/by-name/system_b on /system_root type ext4 (ro,seclabel,noatime,discard,data=ordered) /dev/block/bootdevice/by-name/vendor_b on /vendor type ext4 (ro,seclabel,noatime,discard,data=ordered) /dev/block/bootdevice/by-name/modem_b on /firmware/radio type vfat (ro,context=u:object_r:firmware_file:s0,noatime,uid=1000,fmask=0337,dmask=0227,codepage=437,iocharset=iso8859-1,shortname=lower,errors=remount-ro) /dev/block/bootdevice/by-name/system_b on /system type ext4 (ro,seclabel,noatime,discard,data=ordered) /dev/block/bootdevice/by-name/persist on /persist type ext4 (rw,seclabel,nosuid,nodev,relatime,data=ordered) tmpfs on /storage type tmpfs (rw,seclabel,relatime,size=1902076k,nr_inodes=475519,mode=755,gid=1000) adb on /dev/usb-ffs/adb type functionfs (rw,relatime) /dev/block/bootdevice/by-name/userdata on /data type ext4 (rw,seclabel,nosuid,nodev,noatime,noauto_da_alloc,data=ordered) /dev/block/loop0 on /su type ext4 (rw,seclabel,noatime,data=ordered) /dev/block/loop0 on /system/xbin/su type ext4 (rw,seclabel,noatime,data=ordered)

Output of mount command on Android O Developer Preview rootfs on / type rootfs (rw,seclabel) /dev/root on / type ext4 (ro,seclabel,relatime,data=ordered) tmpfs on /dev type tmpfs (rw,seclabel,nosuid,relatime,size=1897196k,nr_inodes=474299,mode=755) devpts on /dev/pts type devpts (rw,seclabel,relatime,mode=600) proc on /proc type proc (rw,relatime,gid=3009,hidepid=2) sysfs on /sys type sysfs (rw,seclabel,relatime) selinuxfs on /sys/fs/selinux type selinuxfs (rw,relatime) debugfs on /sys/kernel/debug type debugfs (rw,seclabel,relatime) none on /acct type cgroup (rw,relatime,cpuacct) none on /dev/stune type cgroup (rw,relatime,schedtune) tmpfs on /mnt type tmpfs (rw,seclabel,relatime,size=1897196k,nr_inodes=474299,mode=755,gid=1000) none on /config type configfs (rw,relatime) none on /dev/cpuctl type cgroup (rw,relatime,cpu) none on /dev/cpuset type cgroup (rw,relatime,cpuset,noprefix,release_agent=/sbin/cpuset_release_agent) pstore on /sys/fs/pstore type pstore (rw,seclabel,relatime) /dev/block/dm-1 on /vendor type ext4 (ro,seclabel,relatime,data=ordered) /dev/block/sda25 on /firmware/radio type vfat (ro,context=u:object_r:firmware_file:s0,relatime,uid=1000,fmask=0337,dmask=0227,codepage=437,iocharset=iso8859-1,shortname=lower,errors=remount-ro) /dev/block/sdd3 on /persist type ext4 (rw,seclabel,nosuid,nodev,noatime,data=ordered) tmpfs on /storage type tmpfs (rw,seclabel,relatime,size=1897196k,nr_inodes=474299,mode=755,gid=1000) tracefs on /sys/kernel/debug/tracing type tracefs (rw,seclabel,relatime) adb on /dev/usb-ffs/adb type functionfs (rw,relatime) mtp on /dev/usb-ffs/mtp type functionfs (rw,relatime) /dev/block/sda35 on /data type ext4 (rw,seclabel,nosuid,nodev,noatime,noauto_da_alloc,data=ordered) /data/media on /mnt/runtime/default/emulated type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=1015,multiuser,mask=6) /data/media on /storage/emulated type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=1015,multiuser,mask=6) /data/media on /mnt/runtime/read/emulated type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=9997,multiuser,mask=23) /data/media on /mnt/runtime/write/emulated type sdcardfs (rw,nosuid,nodev,noexec,noatime,fsuid=1023,fsgid=1023,gid=9997,multiuser,mask=7)

As you can see in the later output, /storage/emulated is now mounted as type “sdcardfs” which previously was not the case in Android Nougat. Though I haven’t confirmed it myself, the developer of Moonlight Game Streaming, XDA Senior Member cgutman, commented on a recent Google+ post that his angler (Google Nexus 6P) is also using sdcardfs for /storage/emulated. (By the way, you can tell that the Android Nougat device was rooted when running this command, given the two “loop” partitions that binds the superuser binary to /system/xbin/su, systemlessly.)

We’re not surprised to see this kernel change come to Android O. After all, the Googlers who were on the Android Developers Backstage podcast that talked about this change mentioned that this project was one of their next biggest changes coming to the next Android version. This change, though likely not something the average user would notice, is something else to add to the list of subtle, yet ultimately import changes to Android. Though to be fair, other devices from the likes of Samsung (who developed SDCardFS in the first place), Huawei, and OnePlus among others are already utilizing SDCardFS in place of FUSE, so I guess it’s more accurate to say Google is playing catch up here.