Android Spring Clean

By | 2012-07-06

For some insane reason, Google seem to think that the market app should get constantly larger and larger with every update. In essence, it’s a customised web browser — it’s making requests to a server and displaying the appropriate page. Why on earth it’s twice the size of an actual browser, I do not know.

Here’s the top five space users on my HTC Desire

  • Google Play Store: 9.24MB (9.03MB application; 220kB data)
  • k9-mail: 6.75MB (4.09MB application; 2.67MB data)
  • Google+ : 5.95MB (5.4MB application; 564kB data)
  • Browser: 5.84MB (348kB application; 5.5MB data)
  • Maps: 5.09MB (3.95MB application; 1.95MB data)

I am willing to forgive the mail, the browser and the maps — they actually do have a good reason to use lots of data. I don’t even use google+ on my phone; and what in the name of all that is holy does google play need 9MB for?

All it does is make a request to the app server, show the list then download the APK file for installation (an APK being the file that represents an Android App package). I remember when I got the phone the Market app (which is what this Play Store used to be called) was a few MB, and even that was excessive.

Normally a large app you can simply not upgrade, or not use. You don’t get the choice with the market app — it forcibly upgrades itself and cannot be uninstalled.

The HTC desire’s main fault is that the internal phone storage is very small; and the nature of Android is that it stores apps on the internal storage (don’t believe the lies about moving to SD card, Android makes a cached, precompiled version of every app and stores it on the internal storage).

Annoyingly, all this wastefulness has pushed my phone into the “less than 15MB available” state. At which point, Google Talk stops working. DAMNIT. So, spring cleaning time. I’ve got a rooted phone thanks to CyanogenMod so there is scope for a bit more space finding than is normally possible. This article is my notes of what I’ve done.


Let’s look at the state of play to start. I’ve got the Android SDK installed which gives me access to the adb program, and hence adb shell; I’ve also activated USB debugging in the Applications—Development menu. I’ve run that to get a shell on the USB-connected phone (it’s pretty cool that one can do this to a phone). Everything I’ll do will therefore be at the android command line.

# df -h
Filesystem                Size      Used Available Use% Mounted on
tmpfs                   202.8M     32.0K    202.7M   0% /dev
tmpfs                   202.8M         0    202.8M   0% /mnt/asec
tmpfs                   202.8M         0    202.8M   0% /mnt/obb
/dev/block/mtdblock3    250.0M    170.3M     79.7M  68% /system
/dev/block/mtdblock5    147.6M    136.3M     11.3M  92% /data
/dev/block/mtdblock4     40.0M     13.7M     26.3M  34% /cache
/dev/block/vold/179:1    14.8G     12.8G      2.0G  86% /mnt/sdcard

The important partitions are clear here. /system is the readonly operating system. This is the bit that gets upgraded when you do an over-the-air update. It can only (easily) be written to by the bootloader (I might resort to that). /data is the read-write internal phone partition, this is what shows as “phone memory” in the application manager. You can see I’ve got 11.4M free; hence the annoying “phone storage space is getting low” message. /cache is also read-writable but isn’t considered available for any kind of permanent storage. I think HTC made a mistake with that choice. It would be far more flexible to have combined data and cache on one partition to maximise space. You can see that I’ve got another 26.3M free on cache going completely unused. /mnt/sdcard is the SD card (unsurprisingly), it’s not much use to use for my purposes here, it’s holding a lot of the uncompiled versions of apps I have installed so is saving a lot of internal space, but that’s about all it’s good for (in this context), so we’ll have to forget about that 2G that would have solved all our problems.

Let’s go poking in /data then…

# du /data -d 1 -h
17.0K   /data/tombstones
85.5K   /data/app-private
2.0K    /data/dontpanic
85.4M   /data/dalvik-cache
9.9M    /data/app
4.0K    /data/secure
5.5K    /data/property
13.5K   /data/backup
6.0K    /data/local
34.4M   /data/data
50.5K   /data/anr
53.5K   /data/misc
343.5K  /data/system
2.0K    /data/lost+found
130.3M  /data

The major users of space then are /data/dalvik-cache and /data/data. Dalvik is the Android Java engine, and dalvik-cache is where Android stores the compiled versions of your installed apps. When you download an APK you’re getting the Java Bytecode form of an application; the first time you run it it is compiled by Dalvik into a native form (they have a .dex extension, so I’ll call them DEX files). To save time the next time you want to run that application it makes and stores a copy of that compiled version. Here’s a huge design fault in Android:

  • The app won’t run if the APK isn’t present. That is to say that any app stored on the SD card won’t run when the SD card isn’t mounted.
  • The DEX file is always stored on internal phone memory, regardless of where the APK is.

Why couldn’t the DEX version be stored right next to the APK? So if the APK is on SD card, so is the compiled version. Further, why can’t I trade the speed increase from permanently keeping these DEX files gives for the space they take up? A little tick box in the manage applications page to say “hey, I don’t use this app often, I’d rather have the space”. Finally, since Android is calling this a cache why isn’t it managed like a cache — temporary files, oldest unused get sacrificed; and maybe store it on the damned cache partition?

So.. that’s exactly what I’ll do. That 23M on the /cache partition can have some of the crap from /data/dalvik-cache. Note: deleting them would do us no good, as Android will simply remake them exactly where they already are, so any space gain would be very temporary.

# ls /data/dalvik-cache -s | sort -n | tail
  1768 system@app@com.fsck.k9-f2d27042983a87ee3f098df3696fb5bf.apk@classes.dex
  1874 data@app@com.fsck.k9-1.apk@classes.dex
  2290 mnt@asec@com.bskyb.android.skyplus-2@pkg.apk@classes.dex
  2301 system@app@Gmail.apk@classes.dex
  3612 mnt@asec@piuk.blockchain-1@pkg.apk@classes.dex
  4042 data@app@com.android.vending-1.apk@classes.dex
  4047 system@app@Maps.apk@classes.dex
  4422 system@app@Vending.apk@classes.dex
  4686 system@framework@core.jar@classes.dex
  7865 system@framework@framework.jar@classes.dex

It should be no surprise at all to see all the big apps in this list (although they’ve got weird internal filenames instead of the ones we’re used to). What I’m going to do is move some of them to /cache/dalvik-cache and leave symbolic links in their place. That is, essentially, what Android itself should be doing. (I’ve actually already done this before, so my /cache/ partition probably has a little less space than yours).

# mkdir /cache/dalvik-cache

I think I’ll leave the framework items. To avoid busting something fundamental. Two steps for each app: move the dex to /cache/, then create a symbolic link from that new location back to the original location.

I’m using a variable to store the filename for clarity and speed of typing:

# export DEX=system@app@Vending.apk@classes.dex
# mv /data/dalvik-cache/$DEX /cache/dalvik-cache/
# ln -s /cache/dalvik-cache/$DEX /data/dalvik-cache/

You repeat this process for every DEX you want to move, changing $DEX each time. Here’s what I ended up with:

# ls /data/dalvik-cache -s | sort -n | tail
  1646 mnt@asec@com.zegoggles.smssync-2@pkg.apk@classes.dex
  1656 mnt@asec@com.imdb.mobile-1@pkg.apk@classes.dex
  1706 system@app@GoogleDocs.apk@classes.dex
  1768 mnt@asec@com.fsck.k9-1@pkg.apk@classes.dex
  1768 system@app@com.fsck.k9-f2d27042983a87ee3f098df3696fb5bf.apk@classes.dex
  1874 data@app@com.fsck.k9-1.apk@classes.dex
  2290 mnt@asec@com.bskyb.android.skyplus-2@pkg.apk@classes.dex
  2301 system@app@Gmail.apk@classes.dex
  4686 system@framework@core.jar@classes.dex
  7865 system@framework@framework.jar@classes.dex

How are we looking now:

# df -h
Filesystem                Size      Used Available Use% Mounted on
tmpfs                   202.8M     32.0K    202.7M   0% /dev
tmpfs                   202.8M         0    202.8M   0% /mnt/asec
tmpfs                   202.8M         0    202.8M   0% /mnt/obb
/dev/block/mtdblock3    250.0M    170.3M     79.7M  68% /system
/dev/block/mtdblock5    147.6M    124.5M     23.1M  84% /data
/dev/block/mtdblock4     40.0M     29.4M     10.6M  74% /cache
/dev/block/vold/179:1    14.8G     12.8G      2.0G  86% /mnt/sdcard

Better. The /data and /cache free space has reversed. That’ll do me for now. I’ve got a working system again. My temptation for the future will be to do what I said Android should be doing: put the DEX next to the APK. Then the appropriate files will be on the SD card.

A quick check shows me that the moved apps are all still working and that phone is reporting 22.95MB free.

There is another option, which I won’t do this time: moving some applications to the /system partition. That’s a bit tougher though because we would have to mess around with bootloader scripts. I’m satisfied for now, and I’ve left enough space for Google to bloat that damned market app a bit more without killing my phone again.

Leave a Reply