One of the side projects I’ve been working on is to build a simple beaconing app (iOS and Android) to beacon the device’s lat/long onto a Splunk server. This could be used as a way to keep track of test devices or even some kind of geofencing for a device lab.
There are 3 parts to this post:
- Part 1: covers the Android app
- Part 2: covers the iOS app
- Part 3: covers the Splunk set up and custom scripts
For those who do not know, Splunk (splunk.com) is a really cool devops tool that makes it really easy to injest all kinds of logs eg. syslog, apache access logs, log4j etc and makes it really easy to search, create dashboards and alerts with queried log entries. Other than injesting logs, Splunk is also able to listen to a TCP port for events or in version 6.3, allow you to create a simple http event listener that processes events encoded in JSON format.
Some folks will ask, why not use ELK (Elasticsearch, Logstash, Kibana)? I may decide to investigate that at some later point as I strongly believe this is also possible using an ELK stack.
Ok let’s start with the Android app. So I will not cover the basics of creating a simple Android app as there are tons of resources on developer.android.com on how to build one. There are also video courses on Udemy (udemy.com), Lynda.com (now incorporated into LinkedIn) and other online course sites for this. For this entry I assume the reader already knows how to create a simple 1 Activity app, how to create UI elements such as input boxes, buttons and bind them to handlers to execute code.
The code can be found here: https://github.com/foohm71/SplunkBrother
For this post, we’re only interested in the “Android” part. To view and build the code, I would recommend using Android Studio. You can download it from developer.android.com.
If you navigate down the folders in “app/src/main”, you’ll eventually come to 2 files: MainActivity.java and SplunkService.java.
We’ll start with the MainActivity.java first. There are a few more advanced Android concepts here: (a) SharedPreferences and (b) AlarmManager. Most of the code is pretty standard Android code to identify the various UI elements on the activity ie. inputBox, submitButton etc.
You can read more about SharedPreferences here: http://www.tutorialspoint.com/android/android_shared_preferences.htm . Essentially it allows you to persist a set of key-value pairs on the app on the device for retrieval each time the app is run. We use this mechanism to persist a device ID to identify the device in the beaconing.
The code fragment:
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
mDeviceID = settings.getString("deviceID", "");
inputBox.setText(mDeviceID);
Just restores the saved SharePreferences KV pair with key “deviceID” and displays on the inputBox.
If the user changes the value, then we change the value:
SharedPreferences.Editor editor = settings.edit();
editor.putString("deviceID", mDeviceID);
editor.commit();
AlarmManager basically allows you to set up repeated alarms to trigger some code. You can learn more here: http://developer.android.com/training/scheduling/alarms.html
The code below is basically just to set up an alarm to trigger the pingService (we’ll cover this later) every 600000 millis.
Intent intent = new Intent(this, SplunkService.class);
PendingIntent pingService = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pingService);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 600000, pingService);
Next we look at SplunkService.java
There are just a few key things to understand this. (a) You need to have the networking code as AsyncTask and (b) how to use the LocationManager to obtain the lat/long.
In the code, I’ve implemented 2 ways of beaconing to Splunk – via HTTPClient and using Socket. These are pretty standard Java – there’re ton of examples of these in StackOverflow. What is important to note (for newbie Android devs) is that you need to have them encapsulated into an AsyncTask so that they are non blocking. All networking code is blocking and hence can’t be run on the main UI thread for the app. When that happens, Android barfs. Hence the inner classes SendToSplunkHTTP and SendToSplunkSocket.
Now to obtain the location of the device. The code for this is:
LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Location loc = manager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
However you may note that is not what I did here. This I only realized thru testing (hence you should always test!). Basically the problem is that I kept getting NullPointerException for loc object. Reason was that getting the location object is error prone. Hence you should always have a fall back, in my case, I implemented a try-catch block to just give the lat/long as 0,0 if the loc object was null.
More info on LocationManager can be found here: http://www.vogella.com/tutorials/AndroidLocationAPI/article.html and here: http://javapapers.com/android/get-current-location-in-android/
One thing to take note is that to use LocationManager, you need to set permissions on AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>