Android Technical Reference


Requirements

The SDK is supported on all Android versions 2.2 and higher. The SDK requires applications to declare the android.permission.INTERNET permission in the Android Manifest (AndroidManifest.xml). You can declare the following optional permissions to enable additional functionality:

  • android.permission.READ_PHONE_STATE: We recommend that you declare this permission to allow the SDK to retrieve a mobile phone’s serial number. This allows the Medio Platform to accurately identify and report on unique users across all devices and Android OS versions. This permission only applies to phone devices (as opposed to Wi-Fi-only devices).
  • android.permission.ACCESS_NETWORK_STATE: Declaring this permission allows the SDK to check the state of the device’s network connectivity before trying to send data to Medio. The SDK operates most efficiently with this permission so we recommend that you declare it in your manifest. With this permission, the SDK does not need to rely on Android’s underlying HTTP methods to fail when data connectivity is not available. This permission also allows the SDK to collection information about the data network type (e.g., mobile versus Wi-Fi) and whether the user is roaming.
  • android.permission.ACCESS_COARSE_LOCATION or android.permission.ACCESS_FINE_LOCATION: One of these permissions is required if you choose to enable the SDK’s location tracking feature. Choose coarse or fine location depending on how accurate you would like the reported location to be.


SDK Architecture

The diagram below illustrates the high level architecture of the SDK.

android_sdk_architecture


Threading model

The SDK contains no blocking methods and all methods are designed to execute quickly. The methods are synchronized to maintain thread safety. It is safe to make Medio Event API calls on the UI thread, as all blocking operations are done on separate threads.

When your application calls the EventAPI.logEvent method, the SDK creates an Event object. The SDK sets the timestamp automatically in the Event object and also copies all application-defined event parameters into the Event object. Since writing to the SQLite Database is relatively slow, the SDK queues the Event object to a separate background thread and writes it to the database without blocking the application.

When the SDK flushes the events, it again defers the work of collecting all the Event objects to the separate background logging thread. Once the logging thread has collected the events to be sent, the SDK queues the events to another separate background thread. This HTTP thread GZIP compresses the events and HTTP posts the compressed data to the Medio Data Collection Service (DCS) REST API. The HTTP thread then waits for the HTTP response. If Medio DCS accepts the data, then the logging thread removes the events from the database. Note that separate threads are used for compression and HTTP request/response to avoid blocking database access while awaiting the HTTP response. To minimize memory consumption, the SDK may send events to the Medio DCS in several separate batches.


Internal buffer capacity

One very important aspect of the SDK is how it behaves when the internal buffer capacity is reached. The current limit is 1MB. Assuming an average event with strings totals 50 characters (including the event name and key-value pairs), then a 1MB buffer will store approximately 10,000 events.

When the internal buffer capacity limit is reached, the SDK will purge or throw out a small number of the oldest events to make room for new events. This results in data loss but should only happen in extreme situations such as when events cannot be flushed to Medio due to prolonged lack of data connectivity or a misbehaving application logging too many events and disabling flushing.


Flushing events

By default, the SDK automatically flushes events to the Medio Data Collection Service (DCS). You can also flush events on demand by calling the EventAPI.flushEvents method.

Flushing events assumes that a data connection is available and relies on Android’s HTTP implementation to fail gracefully when a data connection is not available. You can make this behavior more efficient by enabling the android.permission.ACCESS_NETWORK_STATE permission.

The SDK spreads the sending of large amounts of events to the Medio DCS over several HTTP Post requests to minimize memory consumption. Once the Medio DCS successfully acknowledges receipt of the events, the SDK removes the events from the Android SQLite database. If the HTTP request fails for any reason, then the events are not removed. The SDK does not immediately retry failed requests. Events that are not sent to the Medio DCS successfully remain queued (stored persistently in non-volatile storage) and will be sent on the next flush either automatically or manually.

The SDK will ignore all other requests to flush if it is already busy with a previous request. New requests to flush will only be accepted after the previous flush has succeeded or failed.

Flushing events and application behavior

The SDK’s automatic flush behavior may not meet every application’s requirements. For example, if you find automatic flushing affecting critical application processing like game play, then you can disable it temporarily during these critical processing points using the EventAPI.disableAutomaticFlushing method. Automatic flushing can be re-enabled again using the EventAPI.enableAutomaticFlushing once the critical processing section is complete. Note your application can still flush events on demand using the EventAPI.flushEvents method while automatic flushing is disabled or enabled.

In extreme cases, you may disable automatic flushing entirely for the life of your application. In this case, we recommend calling the EventAPI.flushEvents method when you perform some other networking activity (if any). If your application does not have any networking activity, then we recommend calling EventAPI.flushEvents during pauses in user interaction. For example, in the case of a game, you may wish to flush events in a “Game Over” screen or a “Main Menu” screen.

If you choose to flush events on demand instead of or in addition to automatic flushing, your application should not call EventAPI.flushEvents too frequently to avoid compromising battery life. On the other hand, you also don’t want to take the risk of losing data by calling EventAPI.flushEvents too infrequently, as old events are purged to allow for new ones when the internal buffer capacity limit is reached.


Session management

The SDK manages sessions according to the rules in the following sequence. Refer to the diagram below to see each step in sequence.

  1. The first time your application calls EventAPI.openSession, the SDK will create a new session (labeled as Session_A in the diagram below).
  2. When your application calls EventAPI.closeSession, the SDK may expire the current session.
  3. If your application calls EventAPI.openSession within 10 seconds of the last call to EventAPI.closeSession, then the SDK will resume the previous session. This behavior means that the SDK will resume the previous session if the user accidentally exits your application and restarts it.
  4. Your application makes the final call to EventAPI.closeSession for Session_A.
  5. If your application calls EventAPI.openSession more than 10 seconds after the last call to EventAPI.closeSession, the SDK will create a new session (labeled as Session_B in the diagram below).



ios_sdk_sessions


Performance and resources

SDK footprint

The size of the SDK and its impact on application size is outlined below:

  • SDK JAR file: 60KB
  • Android APK with SDK (not including application instrumentation): +30KB
  • Android application installed on device with SDK: +100KB
  • Persistent storage used by SDK (not including application events): 12KB
  • Maximum size of SDK SQLite Database for internal buffer: 1MB

Performance measurements

We collected the following performance measurements on an HTC Sensation with a dual core 1.2GHz processor running Android 2.3.3.

Logging and flushing events

The average execution time of the EventAPI.logEvent call is 4.5ms based on 10 test runs of logging 1,000 events (average size 50 characters including name and key-value pairs).

The average execution time of the EventAPI.flushEvents call is 9.8ms based on 10 test runs of flushing 1,000 events (average size 50 characters including name and key-value pairs).

Average time to persist an event

The chart below displays the average execution time for persisting an Event to the database based on 10 test runs of writing 1,000 events with an average size of 50 characters including name and key-value pairs.

android_sdk_persist_event_chart

CPU utilization

The SDK’s CPU utilization during a stress test averaged around 4% over a 30-minute period with auto-flush enabled. The stress test is setup to log 10 events per second and flush events to the Medio DCS after every 500 events logged. Each event is composed of the data shown below equating to an average of 58 characters. This utilization corresponds to 10 events logged per second over a 30 minute period, which is significantly higher than most application logging.

  • Event name: select_next
  • Key-value pair 1: page = stop_page_x
  • Key-value pair 2: select_next = redirect_id_value_x

RAM consumption

The charts below illustrate the RAM usage of the SDK during a stress test. We measured RAM usage by employing the Android community’s accepted methods: Unique Set Size (USS) and Proportional Set Size (PSS).

USS is the set of pages that are unique to a process. This is the amount of memory that is freed when the application is terminated.

android_sdk_ram_uss

PSS is the amount of memory shared with other processes, accounted in a way that the amount is divided evenly between the processes that share it. This is memory that would not be released if the process was terminated, but is indicative of the amount that the process is “contributing.”

android_sdk_ram_pss

The stress test is set up to log 10 events per second and flush events to the Medio DCS after every 500 events logged. Each event in the test was comprised of same data used in the CPU utilization test, equating to 58 characters per event.