ydal

Android 2.2 (“Froyo”) and you: the gritty details behind «Apps to SD»

tl;dr ver­sion: If you can’t use Apps2SD, do adb shell, pm setInstallLocation 2, move any app to SD (igno­ring pos­si­ble “fai­led” errors at first try).

Our beloved Fro­zen Yoghurt came with many new fea­tures wel­come to the com­mu­nity at large, and one fea­ture which had a mixed recep­tion: “Apps on exter­nal sto­rage”, which allows the user to install app­li­ca­ti­ons to its phone’s exter­nal sto­rage — mostly in order to free up inter­nal disk space.

Many custom ROM dis­tri­bu­ti­ons for Android alre­ady had this fea­ture built in, going by the moni­ker “Apps to SD” (or “Apps2SD” or just “A2SD”).

The typi­cal imple­men­ta­tion of A2SD works by using an ext2/ext3 par­ti­tion on the SD card of your device — and usually only works when it’s exactly the second par­ti­tion. For the sake of argu­ment, one such custom imple­men­ta­tion of A2SD will be inclu­ded at the end of this post.

What it then does is just com­ple­tely move all the app­li­ca­ti­ons to the SD par­ti­tion, lea­ving only the /data par­ti­tion behind, and uses a bind mount to fool the sys­tem into belie­ving that the files are still on the same file sys­tem. So, in essence, the a2sd patch “cheats” and pre­tends that not­hing actually has hap­pened while quietly sipho­n­ing the apps to the SD card.

This, of course, only works when you actually have root access to your device and are allo­wed to play around with all the inte­res­ting sys­tem data its­elf. If you’re working on an unrooted/stock hand­set and firm­ware, you don’t have the option of using this fea­ture; and also if you’re too lazy or unkno­wing or prissy to set up an ext[23] par­ti­tion on your SD card.

Thus the «offi­cial» Apps to SD comes into play — if your device is run­ning Android 2.2, that is.

An import­ant thing to note about under­stan­ding the offi­cial imple­men­ta­tion is that it assu­mes that the user has no direct access to the /system par­ti­tion. Espe­cially: the user is not able to access any instal­led Android app­li­ca­tion package in any way that allows copy­ing files.

What Froyo does when instal­ling an app­li­ca­tion to SD is pretty sim­ple: it crea­tes a file on the SD card and uses this as a con­tai­ner to store the app­li­ca­tion in. Said con­tai­ner is used with a cryp­ted loop mount, that is the actual data on the SD card is encryp­ted, and will be decryp­ted at load time when acces­sing the application.

The idea behind this see­min­gly con­vo­lu­ted setup is sim­ple: if you have paid for an app­li­ca­tion, you could just store it on SD and then copy it if it is not encryp­ted. If it is encryp­ted, you can­not access the app­li­ca­tion in a “sim­ple” way to copy (i.e. pirate) it.

Addi­tio­nally, the app­li­ca­tion (with the default set­tings) needs to allow Android to move it to the SD card — other­wise the sys­tem does not enable the func­tio­na­lity, pro­bably to ensure that app­li­ca­ti­ons aren’t “bro­ken” by SD storage.

Of course this is easily man­hand­led by using the USB debug­ging inter­face with adb shell: just issue pm setInstallLocation 2. This tells he package mana­ger (hence «pm») to use the exter­nal sto­rage as a default install loca­tion, which inci­den­tally lifts the block that does not allow an app­li­ca­tion to be stored on exter­nal sto­rage, too.

The down­side:
/dev/block/dm-41 on /mnt/asec/de.hafas.android.db-1 type vfat [...]

And yes, that’s 41 device map­per crypto loops. At least they don’t pro­duce that much over­head as to noti­ce­ably slow down the system.

One of the boons of the Froyo imple­men­ta­tion is that with above com­mand, it can easily be used even with an unroo­ted phone and wit­hout repar­ti­tio­ning your SD drive. The disad­van­ta­ges are that Android requi­res a fair bit of time after boo­ting to mount all the crypto loop devices, which will result in your app­li­ca­ti­ons being acces­si­ble rather late after boo­ting. Also, you will not be able to use wid­gets of any app that is on SD.

Here come the advan­ta­ges of the cust­o­mi­zed A2SD approach: you can still access wid­gets and app­li­ca­ti­ons on your SD card even when it is moun­ted to your com­pu­ter — because Android will only mount away the root par­ti­tion (the FAT one), and not your ext par­ti­tion. And you’ll have less over­head due to the crypto business.

And, as pro­mi­sed, the code that enab­les A2SD on most cur­rent ROMs:

#!/system/bin/sh
#
# Apps2SD using symlinks and bind mounts
# Originally by cyanogen (shade@chemlab.org)
# Modified to use a cleaner /sd-ext implementation by IEF (ief@shadowchild.nl)

# execute any postinstall script then kill it
if [ -e /dev/block/mmcblk0p2 ];
then

    # mount and set perms
    busybox mkdir /sd-ext
    busybox mount -o noatime,nodiratime -t auto /dev/block/mmcblk0p2 /sd-ext;
    busybox chown 1000:1000 /sd-ext;
    busybox chmod 771 /sd-ext;

    # clean up any old symlinks, create data directories
    for i in data;
        do
                if [ -h /data/$i ];
                then
                        rm /data/$i;
                fi;
                if [ ! -d /data/$i ];
                then
                        mkdir /data/$i;
                        busybox chown 1000:1000 /data/$i;
                        busybox chmod 771 /data/$i;
                fi;
        done;

    # don't allow /data/data on sd because of upgrade issues - move it if possible
    if [ -d /sd-ext/data ];
    then
        busybox cp -a /sd-ext/data/* /data/data/;
        busybox rm -rf /sd-ext/data;
    fi;

    # move apps from internal memory to sdcard
    for i in app app-private dalvik-cache;
    do
        if [ ! -d /sd-ext/$i ];
        then
            mkdir /sd-ext/$i;
        fi

        busybox chown 1000:1000 /sd-ext/$i;
        busybox chmod 771 /sd-ext/$i

        if [ -d /data/$i ] && [ ! -h /data/$i ];
        then
            busybox cp -a /data/$i/* /sd-ext/$i/;
            busybox rm -f /data/$i/*;
        fi;
    done;

    # symlink app dirs - they must be on the same filesystem
    for i in app app-private dalvik-cache;
    do
        if [ -d /data/$i ] && [ ! -h /data/$i ];
        then
            busybox rm -rf /data/$i;
            busybox ln -s /sd-ext/$i /data/$i;
        fi;
    done;

    # clean up old whiteouts
    for i in local misc property system tombstones data;
    do
        if [ -h /sd-ext/$i ]; then rm -f /sd-ext/$i; fi
    done;

    # please don't put odex files in the app directory people!
    # it causes dexopt to crash when switching builds!
    busybox rm -f /sd-ext/app/*.odex

    setprop shadow.apps2sd.active 1;

    echo "+++ Apps-to-SD successfully enabled";

else

    # replace symlinks with directories so we can boot without sd
    for i in app app-private dalvik-cache;
    do
       if [ -h /data/$i ];
       then
            rm -f /data/$i;
            mkdir /data/$i;
            busybox chown 1000:1000 /data/$i;
            busybox chmod 771 /data/$i;
        fi;
    done;

    setprop shadow.apps2sd.active 0;
fi;
sync;

This is run as an init script.

One Comment

  1. Anonymous says:

    […] […]

Leave a Reply