Run Google Play on an emulator and pretend to be any device

By August 8, 2012Hacking

Since the beginning of time man has sought to virtualize the human experience. We go to sleep and have life-like experiences in our dreams, we connect to internet sites like Chatroulette to virtually meet strangers (and inadvertently catch a glimpse of some old man balls from time to time), 1995 brought us the classic Denzel Washington/Russell Crowe sci-fi action thriller Virtuosity, and nerds gather in herds online to play StarCraft (myself included) and become virtual intergalactic heroes. The journey to virtualize reality has been a long time coming. The next logical step… to run Google Play on a virtual mobile device? “Of course!” said no one.

Alas, our journey continues. Our odyssey starts with the awesome blog post “Installing Google Play on Android Emulator.” The author, Piotr Buda, was able to successfully install the Google Play application on an emulator. However, you’ll notice that in the comments and subsequent blog post he (and his readers) were unable to download and install applications: the effects of the dastardly Error 491. Additionally, the applications they were able to view were severely limited. After reading both posts, the Apkudo team attempted to take it a step further and a) get downloads working and b) be able to browse and download any app.

Installing Google Play on an Android emulator requires three separate APKs: GoogleLoginService.apk, GoogleServicesFramework.apk, and Phonesky.apk (older versions will be named ‘Vending.apk’.) All three are located in the /system/app/ folder on your device. You can issue an adb pull command to pull each one off of your device (you generally don’t need root to pull). We pulled ours off of a Samsung Galaxy S III (the version of the store that we pulled was 3.5.16)

Next we just push the three APKs to install on the emulator (we made a simple modification to the shell script from the original blog post):

echo "remounting..."
adb remount
echo "pushing login apk..."
adb push GoogleLoginService.apk /system/app/.
echo "pushing framework apk..."
adb push GoogleServicesFramework.apk /system/app/.
echo "pushing vending apk..."
adb push Phonesky.apk /system/app/.
echo "done"

Once the three APKs are installed, it is trivial to get the market executing. You’ll need to enter your account information when prompted and accept the market update if required (the update will generally not be successful, but it doesn’t seem to matter). You should now be able to browse and search the Play Store. Except, of course, you’ll usually hit an Error 491 when you try to download!

Solving Error 491

If you have created your AVD for ICS or earlier you will undoubtedly encounter Error 491 when attempting to download an application. The reason is that a shared object file, is missing from the /system/lib/ folder. You may also find that the DrmProvider.odex and DrmProvider.apk files are missing from the /system/app/ folder. It seems that standard Android AVD images do not include these files. In order to circumvent this, you can build the Android platform from source (see; your AVDs should now include the relevant DRM files. (Note: pulling the .so off of your device and pushing them to the emulator will generally not work.) You can also, of course, just create an AVD for 4.1 Jelly Bean: AVDs that target 4.1 appear to include those missing files and should be able to download applications easily.

Google Play on an emulator.

Move along, not too many apps to see here!

Downloading Solitaire. Side note: I’m pretty good at Solitaire.

Circumventing Google Play Filters

As you browse the Play Store you’ll notice a startling lack of available applications. The Google Play Store filters the apps that you can view based on a handful of factors relating to hardware, software, and carrier. You can find most filters listed here:

Depending on which features you give your AVD, you will see a variety of available apps. However, you’ll still be unable to view a great deal of what the store has to offer simply because your AVD lacks a great many features. Therefore, we’ll need to get our hands dirty with the innards of the Google Play code (this could probably be accomplished in a few other ways, but this was the most practical.)

The basic idea is to capture and mock all of the device identifying information and metadata that Play compiles before it is sent off on the wire. You’ll first need to unzip each APK: unzip {apk} -d {out_dir}. Then, remove the META-INF folder within each (we’ll re-sign each APK later.) Use baksmali on the classes.dex of both Phonesky.apk and GoogleServicesFramework.apk. Now you’ll have access to the smali code for each APK.

Inside the  decompiled GoogleServicesFramework you’ll find a file entitled /com/google/android/gsf/checkin/CheckinRequestBuilder.smali. Poke around a bit, and you’ll notice that it contains a host of device identifying information, all of which we must intercept and mock. Inside the decompiled Phonesky you’ll find two files entitled /com/google/android/finsky/utils/DeviceConfigurationHelper.smali and /com/google/android/finsky/utils/VendingUtils.smali respectively. Again, each file contains device identifying information that Google Play will eventually serialize, send off into the cloud, and use to filter the apps that you can view on the store.

So now that we know what data is being sent, how do we intercept it and mock it?  First, you’re going to need data to mock. This is relativley simple, as you can pull most of that information from a real phone using some combination of adb shell getprop, adb shell pm, and adb shell dumpsys. On the other hand, you can build a simple application that pulls all of this data and dumps it out in a neat little file. The next step is to build a framework for mocking data. I built a java class composed entirely of static methods (it is very easy to hand insert into smali code (with some register finagling)) that I compiled and then decompiled back into smali. Inside each of the decompiled Google APKs, make the appropriate directories for your classes package, and copy over the smali file. You should now be able to call any of your static methods from Google code.

Now its a matter of using grep to find the right method calls in the files mentioned above. For each method found, comment it out, and insert your own, mocked method call.  For example, in DeviceConfigurationHelper.smaliI’ve replaced the call

invoke-virtual {v4}, Landroid/content/pm/PackageManager;->getSystemAvailableFeatures()[Landroid/content/pm/FeatureInfo;

with a call to my own getSystemAvailableFeatures() method. Finally, you’ll need to use smali to re-compile all of the code back into a classes.dex file (replace the old ones in Phonesky and GoogleServicesFramework respectively), re-zip into each into an apk (including GoogleLoginService), and re-sign each using jarsigner. Push them onto the emulator as always and you should be good to go.

Play thinks we’re a Galaxy Nexus!

Downloading Angry Birds Space.

Playing our downloaded app on the emulator!

For now, you can only download and install free apps. As you might imagine, getting paid apps on an emulator is a bit trickier. We’ll save that for a later post.

Happy hacking,

-Daniel Joyce, Software Engineer

You may wish to reference the following:
Smali and Baksmali
Android Api
Google Play Filters

Leave a Reply