ApkRunner – Automating APK Installation and Execution in Android Emulator

Do you remember when batch scripting was cool? 

Yeah, me neither..

But not because it was never cool, no. It’s just because some time between then and now I went to college and partied a good amount, which undoubtedly had a negative effect on my ability to recall things. Anyway…

Despite of what some people, who should probably stick to “overseeing license compliance”,  might think, the apps from various Android markets have shown ability to do some shady things and the expectation that the underlying app markets will catch and remove those apps themselves is a solid case of hubris. (Whether malware infestation is a case of PEBCAK or a platform design flaw is really irrelevant). As such, it is quite useful to be able to capture application behavior in some sort of automated fashion, so it can be analyzed. Needless to say, this is also useful for automated testing and other such nonsense.

 

QA

 

The analysis bit clearly involves proprietary IP and I am not going to go there, but I thought I’d share some gangsta batch script madness that enables us to automatically run an arbitrary Android application in an emulator. What makes this generic is that the script does the legwork to determine the activity that should be launched and handle installation and subsequent cleanup (sort of).

So..

Given an arbitrary APK and the name of the AVD to use, the script below does the following:

  • Uses apktool to get the name of the package and launchable Activity from the APK’s manifest (AndroidManifest.xml)
  • Launches a clean instance of the emulator with the specified AVD
  • Installs the APK in the emulator
  • Launches the launchable activity identified in step 1
  • Waits a little while (here you can do some monitoring or monkeying around with MonkeyRunner)
  • Shuts down the emulator
  • Stores the LogCat file

Prerequisites include:

  • Java
  • Android Apk Tool
  • Android SDK
  • An existing AVD that can be used by the emulator
  • Notepad, Notepad++ or any other text editor (if modifications are desired)
  • Some common sense

WARNING: the script will wipe all the img files assocaited with the AVD, meaning it will erase all user data and applications already installed inside the AVD. If that is not what you need, you’ll need to modify the script to not erase the image files, and perhaps have the APKs uninstalled manually (by deleting the APK file from the emulated device)

So I was running thin in a Windows XP VM and found that there are a couple of issues that warranted workaround instead of solutions.. Namely:

  • ‘adb emu kill’ did not kill. I had to use pskill to forcefully kill the emulator
  • when installing the apk, ‘wait-for-device’ flag did not wait long enough and started installing before the emulator booted fully. So instead, I used a sleep of 65 seconds to let the emulator boot. Obviously, this will vary for different machines and images, so you will need to tweak this.

In order to get this to work you will need to modify some variables in the script:

_emuPath – this should be a full path to the emulator executable
_adbPath – this should be a full path to adb
_aaptPath – this should be a fill path to the adnroid apk tool exectuable
_avdImagePath – path to where the AVD configuration and image files are stored
_emuBootWait – number of seconds to wait for emulator to start
_apkRunTime – number of seconds to wait before terminating the emulator

Points of interest: the script ‘sleeps’ a specified number of seconds by pinging 127.0.0.1.

Shortcomings..

Well, this snippet is just the beginning.. In reality, the script could and should be extended to account for possibility of multiple launch activities, accommodate launching services, check for errors, support multiple emulator instances, etc.

I hope this is useful and please get back with your comments and suggestions,

Cheers!

@echo off
:: Script: ApkRunner.bat
:: Author: Timur Kovalev (timur@creativecodedesign.com)
:: Url: http://www.creativecodedesign.com
:: Notes: requires Java, Android SDK and android apk tool (http://code.google.com/p/android-apktool/)

setlocal EnableDelayedExpansion
:: Change variables below as needed
set _logCatPath=logCatDump.log
set _emuPath="C:\Program Files (x86)\Android\android-sdk\tools\emulator.exe"
set _adbPath="C:\Program Files (x86)\Android\android-sdk\platform-tools\adb.exe"
set _aaptPath="C:\Program Files (x86)\Android\apktool\aapt.exe"
set _avdImagePath=%HOMEDRIVE%%HOMEPATH%\.android\avd
set _emuBootWait=65
set _apkRunTime=60
:: Check if all the parameters have been supplied by checking if he got the last one
if [%2]==[] goto Usage
set _apkPath=%1
set _avdName=%2

:: First get the required info out of the APK
set _returnLabel=startEmulator
goto GetApkInfo
:startEmulator

echo Deleting Android Virtual Device State...
del "%_avdImagePath%\%_avdName%.avd\*.img"

echo Starting Emulator...
%_emuPath% -no-boot-anim -avd %_avdName% -logcat -shell > %_logCatPath%
ping -n %_emuBootWait% 127.0.0.1 > nul

echo Installing %_apkPath% in the Emulator
%_adbPath% -e wait-for-device install %_apkPath%

echo Launching %_launchActivity%...
%_adbPath% -e shell am start -a android.intent.action.MAIN -n %_launchActivity%
ping -n %_apkRunTime% 127.0.0.1 > nul

echo Done! Terminating...
:: adb emu kill does not work on Windows.. force-killing
taskkill /IM emulator-arm.exe
goto End

:GetApkInfo
:: ***** Get The Package Name and Activity Name from the APK ****
:: dump the apktool info into a temp file
%_aaptPath% dump badging %_apkPath% > ApkInfo.txt
:: get the lines that contain the package and launchable activity info
for /f "delims=" %%G in ('findstr /C:"package: name='" ApkInfo.txt') do SET _packageName=%%G
for /f "delims=" %%G in ('findstr /C:"launchable activity name" ApkInfo.txt') do SET _activityName=%%G
:: split the string using quotes, and extract the part we need
for /f "tokens=1,2,3 delims='" %%G in ("%_packageName%") do set _packageName=%%H
for /f "tokens=1,2,3 delims='" %%G in ("%_activityName%") do set _activityName=%%H
:: now get the package name out of the activity name
set _activityName=!_activityName:%_packageName%=/!
set _launchActivity=%_packageName%%_activityName%
@echo Package : %_packageName%
@echo Activity : %_activityName%
@echo Launchable: %_launchActivity%
del ApkInfo.txt
goto %_returnLabel%

:Usage
@echo.
@echo *************************************************************
@echo * Usage: *
@echo * ApkRunner.bat [APK] [AVD name] *
@echo * [APK] - path to the apk file to install and run *
@echo * [AVD Name] - name of a configured AVD *
@echo *************************************************************
:End

endlocal