A user could receive and view data that is not theirs, and we must prevent this from happening in a secure application. Here is a diagram of how this could happen:
This only works for Retrofit 2 calls, but not all networking calls made through okhttp 3.
Option 2:
When the client session is invalidated, use okhttp 3’s Dispatcher to cancel all running and queued calls.
PROS:
Very effective. All calls would immediately be cancelled.
CONS:
If there is a call like “Update Profile” that is still occurring, it would be cancelled, which is not desirable.
If there is an unauthenticated call happening, you’d have to ensure that was being executed on non session sensitive Retrofit 2 or okhttp 3 instance to avoid unwanted termination.
Option 3:
Same as the previous option, but instead occurs when a new client session is started, instead of when an old one ends.
PROS:
Very effective. All calls would immediately be cancelled.
CONS:
You would have to ensure this code got run before you kicked off any session sensitive calls, otherwise they would be immediately cancelled.
If there is an unauthenticated call happening in the background, you’d have to ensure that was being executed on non session sensitive Retrofit 2 or okhttp 3 instance to avoid unwanted termination.
Option 4:
Using an okhttp 3 Network Interceptor to return back an HTTP Response with a custom response code like 999 and removing the response body.
PROS:
Will work for:
All okhttp 3 calls.
Retrofit 2 Callback calls.
Retrofit 2 RxJava calls.
CONS:
It will appear like the HTTP response came back from the server so you will have to have custom logic in your response handler to check and see if this response has a HTTP status code of 999.
It feels a little “hacky”… but would prevent the security hole.
Option 5: (My Choice)
Using an okhttp 3 Network Interceptor to throw a custom SessionMismatchException when this problem is detected, and handle the Exception appropriately.
PROS:
Will work for:
All okhttp 3 calls
Retrofit 2 Callback Calls
Retrofit 2 RxJava Calls
This is truly an “Exception” scenario, so this makes sense.
The request is executed fully, but will not be received by the client. (This could be a “con” depending on your use case)
CONS:
You must code your onFailure and onError handlers to appropriately handle this SessionMismatchException type.
If you just extend IOException, okhttp 3 will by default retry the HTTP call. However, if you extend java.net.SocketTimeoutException, okhttp 3 will not retry.
My Choice: Option 5, throwing a custom SessionMismatchException. This seemed to be the most flexible and intuitive since this truly is an Exception/Failure case. I’ve provided a sample implementation of this below.
Assumption: You have a “SessionManager” in your Android code which is aware of the current session.
I Googled all around to try and figure out how to tweak Android Emulator virtual devices (AVDs) via the command-line. The Android Emulator documentation online has some options for running the emulator, but it didn’t allow me to specify memory at runtime, and many other things I wanted to customize. There is also documentation specific to the creation of AVDs (vs just the running of them on the emulator), but that kept referring to the UI tools for it. I’ve gotten so used to Googling for help, that I didn’t think of running help locally :-p
emulator -help
That gives us a LOT of options that are not documented on the website including.
Android Emulator usage: emulator [options] [-qemu args]
options:
-list-avds list available AVDs
-sysdir <dir> search for system disk images in <dir>
-system <file> read initial system image from <file>
-writable-system make system image writable after 'adb remount'
-datadir <dir> write user data into <dir>
-kernel <file> use specific emulated kernel
-ramdisk <file> ramdisk image (default <system>/ramdisk.img
-image <file> obsolete, use -system <file> instead
-initdata <file> same as '-init-data <file>'
-data <file> data image (default <datadir>/userdata-qemu.img
-partition-size <size> system/data partition size in MBs
-cache <file> cache partition image (default is temporary file)
-cache-size <size> cache partition size in MBs
-no-cache disable the cache partition
-nocache same as -no-cache
-sdcard <file> SD card image (default <system>/sdcard.img
-snapstorage <file> file that contains all state snapshots (default <datadir>/snapshots.img)
-no-snapstorage do not mount a snapshot storage file (this disables all snapshot functionality)
-snapshot <name> name of snapshot within storage file for auto-start and auto-save (default 'default-boot')
-no-snapshot perform a full boot and do not do not auto-save, but qemu vmload and vmsave operate on snapstorage
-no-snapshot-save do not auto-save to snapshot on exit: abandon changed state
-no-snapshot-load do not auto-start from snapshot: perform a full boot
-snapshot-list show a list of available snapshots
-no-snapshot-update-time do not do try to correct snapshot time on restore
-wipe-data reset the user data image (copy it from initdata)
-avd <name> use a specific android virtual device
-skindir <dir> search skins in <dir> (default <system>/skins)
-skin <name> select a given skin
-no-skin don't use any emulator skin
-noskin same as -no-skin
-dynamic-skin dynamically construct a skin of given size, requires -skin WxH option
-memory <size> physical RAM size in MBs
-accel <mode> Configure emulation acceleration
-no-accel Same as '-accel off'
-ranchu Use new emulator backend instead of the classic one
-engine <engine> Select engine. auto|classic|qemu2
-netspeed <speed> maximum network download/upload speeds
-netdelay <delay> network latency emulation
-netfast disable network shaping
-code-profile <name> enable code profiling
-show-kernel display kernel messages
-shell enable root shell on current terminal
-no-jni disable JNI checks in the Dalvik runtime
-nojni same as -no-jni
-logcat <tags> enable logcat output with given tags
-no-audio disable audio support
-noaudio same as -no-audio
-audio <backend> use specific audio backend
-raw-keys disable Unicode keyboard reverse-mapping
-radio <device> redirect radio modem interface to character device
-port <port> TCP port that will be used for the console
-ports <consoleport>,<adbport> TCP ports used for the console and adb bridge
-onion <image> use overlay PNG image over screen
-onion-alpha <%age> specify onion-skin translucency
-onion-rotation 0|1|2|3 specify onion-skin rotation
-dpi-device <dpi> specify device's resolution in dpi (default 165)
-scale <scale> scale emulator window (deprecated)
-http-proxy <proxy> make TCP connections through a HTTP/HTTPS proxy
-timezone <timezone> use this timezone instead of the host's default
-dns-server <servers> use this DNS server(s) in the emulated system
-cpu-delay <cpudelay> throttle CPU emulation
-no-boot-anim disable animation for faster boot
-no-window disable graphical window display
-version display emulator version number
-report-console <socket> report console port to remote socket
-gps <device> redirect NMEA GPS to character device
-keyset <name> specify keyset file name
-shell-serial <device> specific character device for root shell
-tcpdump <file> capture network packets to file
-bootchart <timeout> enable bootcharting
-charmap <file> use specific key character map
-prop <name>=<value> set system property on boot
-shared-net-id <number> join the shared network, using IP address 10.1.2.<number>
-nand-limits <nlimits> enforce NAND/Flash read/write thresholds
-gpu <mode> set hardware OpenGLES emulation mode
-camera-back <mode> set emulation mode for a camera facing back
-camera-front <mode> set emulation mode for a camera facing front
-webcam-list lists web cameras available for emulation
-screen <mode> set emulated screen mode
-force-32bit always use 32-bit emulator
-selinux <disabled|permissive> Set SELinux to either disabled or permissive mode
-qemu args... pass arguments to qemu
-qemu -h display qemu help
-verbose same as '-debug-init'
-debug <tags> enable/disable debug messages
-debug-<tag> enable specific debug messages
-debug-no-<tag> disable specific debug messages
-help print this help
-help-<option> print option-specific help
-help-disk-images about disk images
-help-keys supported key bindings
-help-debug-tags debug tags for -debug <tags>
-help-char-devices character <device> specification
-help-environment environment variables
-help-keyset-file key bindings configuration file
-help-virtual-device virtual device management
-help-sdk-images about disk images when using the SDK
-help-build-images about disk images when building Android
-help-all prints all help content
I hope you found this from YOUR Google search about this, and it helped 🙂
I had a long standing issue where I could only launch two emulators on my Macbook Pro simultaneously. Any other emulators would launch and get a black screen and wouldn’t load. I accepted this as fact, and carried on with life.
Finally today I found the need to figure out “why” this was the case as I wanted to start sharding my Android UI tests to speed them up. I was given the suggestion that it could be the # of CPUs or the amount of RAM. If you look in the logs you may see something like this (if you launch the emulator from android avd):
or you may see:
“HAXM does not have enough memory remaining to load this AVD.”
In order to change your memory allocation for HAXM, you need to re-install it, so run the installer again which is a DMG at: [$ANDROID_HOME/sdk/extras/intel/Hardware_Accelerated_Execution_Manager/ ] and this time select more memory. [HAXM Technical Docs]
But… before you install, make sure you have the latest version. The latest version as of September 7th, 2016 is 6.0.3 (Which was released on June 21, 2016).
On my Macbook, I was given 2048MB of memory by default which allowed me to run 2 emulators simultaneously (as seen above).
I have 16GB total memory though, so lets make it so I can run a bunch of emulators at once by allocating 8GB 🙂
Here is my Macbook Pro running 6 Android emulators simultaneously after the changes:
I’m excited to announce I’ve been accepted to talk at a bunch of upcoming events.
Espresso: A Screenshot is Worth 1,000 Words
Do your product owners, designers and the people that pay you understand what in the world your Espresso tests are doing and why they are valuable? You’ve spent so much time and effort writing these tests and your whole team deserves to get the most benefit out of them. In this talk you’ll learn how to setup your Espresso tests to take programatic screenshots, and leverage the Robot pattern of testing for clean, readable, and maintainable tests. You’ll also learn guidelines on when it’s appropriate to write Espresso tests instead of Robolectric or Unit tests, and how to leverage mock data to make your Espresso tests run with Tesla-like speed.
I have architected the Espresso test setup for our Capital One Wallet Android team and helped execute our ongoing continuous integration efforts. We’ve seen a 4x+ speed improvement over Appium, have more maintainable tests, and now have visibility for anyone to look into our test coverage.
The last few days I have been struggling to get the Android Emulator to connect to certain domains through a proxy we have at my job. Because of this, I started messing with my OS X DNS configuration and got myself in a DNS mess. I finally figured my way out, so I wanted to share with you how DNS works with the Android Emulator, and hopefully avoid the troubles I ran into.
The Android Emulator uses the DNS settings of your OS X machine from/etc/resolv.conf as mentioned above. The file looks something like:
#
# Mac OS X Notice
#
# This file is not used by the host name and address resolution
# or the DNS query routing mechanisms used by most processes on
# this Mac OS X system.
#
# This file is automatically generated.
#
search fios-router.home
nameserver 192.168.1.1
This file is re-generated by OS X as you connect to different networks (different WiFi hotspots or ethernet connections) to properly resolve DNS entries while connected to that network.
The thing I didn’t know is that /etc/resolv.conf is by default a symbolic link to /var/run/resolv.conf. So, if you ever mess with /etc/resolv.conf and want to put back the original, you’ll have to re-create the symbolic link on your system, so that your global overrides are no longer in place. Create the symbolic link using the following command:
sudo ln -s /var/run/resolv.conf /etc/resolv.conf
Anyways, you can override your DNS entries for the Android Emulator via the command line using the “-dns-server” option, or you can edit /etc/resolv.conf and override it globally. Just realize that you need to create a symbolic link to /var/run/resolv.conf in order to “revert” changes if you mess with /etc/resolv.conf.
Happy DNS’ing with the Android Emulator and I hope for your case you don’t ever have to deal with it!
I spent the last few weeks figuring out how to get our Android Tests running on our Jenkins CI (Continuous Integration) server using the latest Android Emulator. I am sharing what I learned so that I can hopefully help someone else and so I can refer back to it in the future.
Result of this tutorial/example:
You will be able to programmatically create an Android Emulator AVD (Android Virtual Device), start it, wait for it to load, run your tests, then kill the emulator, generate a Spoon html test report.
Assumptions for this example:
You have the Android SDK configured on this machine with:
SDK components for API 23
The latest build tools
Google apis support
API 23, x86_64 with Google APIs Image
HAXM support installed
You have an Android build flavor named “qa”.
You are running your tests on a “debug” build.
You have built the APK and test APK with:
./gradlew clean app:assembleQaDebug and app:assembleQaDebugAndroidTest
You have Android tests in a Java package called “integration_tests”
spoon-runner-1.2.0-jar-with-dependencies.jar exists in your working directory.
You want to use an API 23, x86_64, Google APIs enabled AVD (Note, you could easily change these, but this is what this example uses)
To download all the necessary SDK components referenced above, you can run the following command, or just download the components using the UI version of the Android SDK Manager. NOTE: These commands aren’t scripted for a CI server. You have to manually accept licensing terms:
Kill this emulator instance after our tests complete
#CONFIG
FLAVOR="qa"
PACKAGE_NAME="com.example.myapp"
AVD_NAME="integration-tests"
PORT=6000
##############################################################################
#Ensure the Test APK is built already.
TEST_APK_FILE="app/build/outputs/apk/app-${FLAVOR}-debug-androidTest-unaligned.apk"
if [ ! -f "${TEST_APK_FILE}" ]
then
echo "androidTest APK doesn't exist, exiting. Make sure you run ./gradlew app:assembleQaDebug app:assembleQaDebugAndroidTest"
exit
else
echo "androidTest APK Exists, continuing"
fi
#Calculate the Serial Number of the emulator instance
SERIAL=emulator-${PORT}
echo "Creating (forceful) AVD with name ${AVD_NAME}"
# We have to echo "no" because it will ask us if we want to use a custom hardware profile, and we don't.
echo "no" | android create avd \
--name "${AVD_NAME}" \
--target "android-23" \
--abi "google_apis/x86_64" \
--skin "WXGA720" \
--force
echo "AVD ${AVD_NAME} created."
#Start the Android Emulator
#"2>&1" combines stderr and stdout into the stdout stream
START_EMULATOR="emulator \
-avd ${AVD_NAME} \
-netspeed full \
-gpu on \
-netdelay none \
-port ${PORT}"
echo $START_EMULATOR
$START_EMULATOR 2>&1 &
#Ensure Android Emulator has booted successfully before continuing
EMU_BOOTED='unknown'
while [[ ${EMU_BOOTED} != *"stopped"* ]]; do
sleep 5
EMU_BOOTED=`adb -s ${SERIAL} shell getprop init.svc.bootanim || echo unknown`
done
duration=$(( SECONDS - start ))
echo "Android Emulator started after $duration seconds."
# Get the file name of the QA APK (we need to cope with the version number changing)
APK_LIST_AS_TEXT="$(ls -t app/build/outputs/apk/*-android-debug-*-${FLAVOR}.apk)"
APK_FILES=( $APK_LIST_AS_TEXT )
# Use the Spoon utility as a test runner
SPOON_COMMAND="java -jar spoon-runner-1.2.0-jar-with-dependencies.jar \
-serial ${SERIAL} \
--apk ${APK_FILES[0]} \
--test-apk ${TEST_APK_FILE} \
--no-animations \
--fail-on-failure \
--debug
echo "Running: ${SPOON_COMMAND}"
${SPOON_COMMAND}
#Stop the Android Emulator
echo "Killing the Android Emulator with serial: ${SERIAL}"
adb -s ${SERIAL} emu kill
Final notes & tips:
Because the Android Emulator’s serial number is in the format of “emulator-{SERIAL}”, it is very important to start the emulator on a specific port (using the “-port {PORT}” param) so that you can reference the image by serial number. This allows you to launch more than one emulator on the same build machine.
Command to list available Android platforms
android list targets
Command to list available AVDs
android list avd
Command to list all available SDK components that you can –filter for in the “update sdk” command:
WireMock includes the following features out of the box which are very valuable in a wide variety of development and testing scenarios:
HTTP response stubbing, matchable on URL, header and body content patterns
Request verification
Runs in unit tests, as a standalone process or as a WAR app
Configurable via a fluent Java API, JSON files and JSON over HTTP
Record/playback of stubs
Fault injection
Per-request conditional proxying
Browser proxying for request inspection and replacement
Stateful behaviour simulation
Configurable response delays
It’s true you don’t have to put WireMock on your Android device to use it. You can also just run WireMock on a computer and get a lot of benefit out of this by pointing your HTTP calls to your computer. This can be very useful during development and testing, but will require you to manage these mock files separate from your Android application. When you run WireMock on your computer, you’re creating a configuration dependency which is challenging to maintain for scripted testing scenarios. By including WireMock in your Android project and starting the server programmatically, you are able to remove the dependency of having to run an external server.
Here are your build.gradle dependencies to bundle WireMock 2.0.8-beta into your Android project:
compile("com.github.tomakehurst:wiremock:2.0.8-beta") {
//Allows us to use the Android version of Apache httpclient instead
exclude group: 'org.apache.httpcomponents', module: 'httpclient'
//Resolves the Duplicate Class Exception
//duplicate entry: org/objectweb/asm/AnnotationVisitor.class
exclude group: 'asm', module: 'asm'
//Fixes Warning conflict with Android's version of org.json
//org.json:json:20090211 is ignored for debugAndroidTest as it may be conflicting with the internal version provided by Android.
exclude group: 'org.json', module: 'json'
}
//Android compatible version of Apache httpclient.
compile 'org.apache.httpcomponents:httpclient-android:4.3.5.1'
If you want an example of what it looks like to use a bundled WireMock instance in an Android test, check out an examples repository on GitHub I put together to show this.
Here is an Espresso Test from the examples project:
@RunWith(AndroidJUnit4.class)
public class WireMockActivityInstrumentationTestCase2 extends ActivityInstrumentationTestCase2 {
private MainActivity activity;
public WireMockActivityInstrumentationTestCase2() {
super(MainActivity.class);
}
@Rule
public WireMockRule wireMockRule = new WireMockRule(BuildConfig.PORT);
@Before
@Override
public void setUp() throws Exception {
super.setUp();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
activity = getActivity();
}
@Test
public void testWiremock() {
String jsonBody = asset(activity, "atlanta-conditions.json");
stubFor(get(urlMatching("/api/.*"))
.willReturn(aResponse()
.withStatus(200)
.withBody(jsonBody)));
String serviceEndpoint = "http://127.0.0.1:" + BuildConfig.PORT;
activity.setWeatherServiceManager(new WeatherServiceManager(serviceEndpoint));
onView(ViewMatchers.withId(R.id.editText)).perform(typeText("atlanta"));
onView(withId(R.id.button)).perform(click());
onView(withId(R.id.textView)).check(matches(withText(containsString("GA"))));
}
}
If you’re using WireMock for only testing or mock scenarios, you can justify the dependency overhead of including the library because of it’s vast array of features. But, I wouldn’t suggest embedding it into your normal app as it has a very large method count and size footprint. Here’s a breakdown of how big WireMock and it’s dependencies are:
That puts us at a total of 54,691 methods if you include WireMock 2.0.8-beta in your project by itself. Wowsa, that’s a lot, especially with Android’s 65,000 Method Limit (which can be circumvented using a technique called MultiDex).
Dependency exclusions & inclusions for WireMock to run on Android:
My recommendation: If you need the features WireMock provides, go with it. It’s sexy and it works well. WireMock has a lot of bang for the buck, and you’re only taking this overhead in test and mock build flavors. If you’re looking for something WAY more basic on Android, try okhttp’s MockWebServer project. It does allow you to run an HTTP server within your app but it’s very limited and that makes it lightweight. You can queue up responses in a row, or create a custom “dispatcher” which allows you to choose which response to send back based on a request. It really depends on your use cases as to which one you choose. There is also an example of MockWebServer being used in the same AndroidHttpMockingExamples project on GitHub. Note: the examples are there mostly for configuration but don’t exercise all of WireMock’s features. In this examples project, you will see that MockWebServer is an equally viable solution because of the simplicity of this use case.
The latest version of okhttp’s MockWebServer has 20,453 methods, but that includes okhttp and junit which you are probably already using in your project. The biggest culprit is BouncyCastle (a java implementation of many encryption algorithms) which has 15,163 on it’s own.
Related Info: If you just want a little more info and more advanced use cases about how to use WireMock on Android using Espresso UI tests, Michael Bailey has a great talk up on YouTube from 2014. He talks about how he used an embedded WireMock instance on Android that he hacked together for version 1 of WireMock (library is not publicly available). He shows some really good examples and I highly recommend watching the talk.
Finally: One thing I haven’t figured out how to do on Android yet is to use the “__files” and “mappings” directories the same way you can on a computer. If anyone knows how to get this to work, or a nice work-around, please let me know.
Are you using WireMock on Android? If so, please let me know on Twitter by tweeting @HandstandSam, I’d love to know.
This article is a quick overview on the types of Android processor instruction set types, known as an ABI (Application Binary Interface) and how to determine which ones your device supports.
In order to include any compiled native C libraries, such as “mylib.so” into your Android application, it needs to be compiled it for a specific ABI.
ABIs found on Android are in 3 categories:
ARM
armeabi
armeabi-v7a (Typically also supports armeabi)
arm64-v8a (Typically also supports armeabi and armeabi-v7a)
X86
x86
x86_64 (Typically also supports x86)
MIPS
mips
mips64 (Typically also supports mips)
When including native libraries into your app, you’ll typically see them packaged within an AAR dependency, but sometimes you will have to add them manually. When you have to add them manually you will have to structure your dependencies to tell which ABI the code is compiled for.
For example:
app/libs/armeabi/mylib.so or
app/libs/x86/mylib.so
“armeabi-v7a” is BY FAR the most widely seen ABI on Android. About 90+% of all phones made in the last few years supports this. x86 is only on a few devices including the The Asus Zenphone 2, Genymotion Emulator and some Android Emulator images. I’ve never even heard of any modern android device using a “mips” based processor.
To figure out what type of ABI your Android device has, you have two methods. You can do it with an ADB (Android Debug Bridge) command, or programmatically through code.
Ensures a client is connecting over HTTPS to the intended server ONLY and no other. This is achieved by including public server certificate information on the client and not relying on the device’s trust store (such as the one on Android or the JVM).
This trust store can be augmented by adding in additional Certificate Authority (CA) Certs and then HTTPs traffic can still be monitored. A common development use of monitoring HTTPS traffic is using Charles Proxy.
depth=2 /C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
verify error:num=20:unable to get local issuer certificate
verify return:0
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhtxFolwNJBGuhYRGDiNF
2Av9jTt0c2vk5mLBrO9td2hFyvw0B0fPpxbkOm72Cd4OnGVXxIB0hp1XRWXuyP+p
FMHmXSshVWDIrcAwjR5r+WnAqrLacZJNHkDOWO+COY8CUHGTn9YfwKwuHQROp6aH
Yu7YhppMXu3dL1kZ55AzYdwgYVc6BdxmDsGWRZbgZ0qt/QQC0zmbR+hLpZAKhHmN
VnBRXYz5q+XLEBmjQnwVmwMzPCvZFzNEWan0wQsCRqcJ19lO5hLxn4O2T718qF2h
cd1sH1RL6HlhUxJe09L3yoGCMoENIq6ywIrVgFsZtyhg8TMyCZuRtyCS+ux9ma0A
7wIDAQAB
-----END PUBLIC KEY-----
It’s been super hard to not share this info as I’ve done presentations on Host Card Emulation (HCE) presentations, but on October 14th the feature I’ve been leading Android development efforts on launched! Capital One Wallet – Google Play Store. This is a project I’ve been a part of for almost a year and it’s so cool to see it in the wild and right along side of Android Pay, Samsung Pay and the rest. It supports Visa and Mastercard and is pretty awesome. Capital One was the first bank in the US to support contactless payments in an Android app and it’s super exciting to have been a part of that.
I tried to do my with presentations but it always killed me that I wasn’t able to share what we were doing. I did feel like I was able to explain how HCE works on Android, but wasn’t able to give much more info at the time. Check out my presentation video and slides from Droidcon NYC.