Thursday, July 25, 2013

Automating Android Testing

So, I am dealing now with improving the performance of an Android app I am working on.
The app is an education app where users can view their books, collaborate and do many more things. There are many things happening in this app, and some of them negatively impact the user experience in terms of performance and responsiveness.
As I am approaching the task, I decided that I must have some ways to measure the current performance of the app, and its various parts.
I basically want to perform a user operation, and measure the time it takes the app to respond.
Assuming the way this works is:
User Input -> Various lengthy operations -> Display updated
If I can improve the lengthy operations performance, I will get a better user experience.
To establish a method for measuring the performance and any progress I make, and not just basing this on subjective feeling, I wanted to make some automated framework, whereby a script can activate user actions, and report back the time it took the app operations until the desired feedback is presented to the user.
There are various methods described elsewhere, some rely on accessibility and automating various widget actions based on that. In my case, I do not have widgets, and I wanted a simpler way.
So my simple solution consists of a small footprint web server (or http daemon) embedded in my app. I based this on Nano HTTPD: https://github.com/NanoHttpd/nanohttpd which is a very simple http daemon you use by subclassing the NanoHTTPD class.
When you subclass NanoHTTPD, you are expected to override the serve method to respond to http requests.

I wrote mine to look for parameters in the query string this way:



public Response serve(String uri, Method method, Map headers,
   Map parms, Map files) {
 for (Map.Entry kv : parms.entrySet()) {
  String key = kv.getKey();
  String strValue = kv.getValue();
  if (key.compareTo("cmd") == 0) {
   _callbackHandler.TA_PerformCommand(strValue);
   break;
  }
  else {
   Log.d("httpd", "Invalid param: " + key);
  }
  final String html = "Command Received";
  return new NanoHTTPD.Response(Response.Status.OK, MIME_HTML, html);
 }

The callback handler is an object passed to the constructor of my NanoHTTPD sub-class.

Since some of the operations I try to measure take time, and I want to measure that time, I added logic to my serve method to wait and sleep (since it is anyway being run on a separate thread) until the operation is done, and to report back the timing of this operation. This is the basic code:



public Response serve(String uri, Method method, Map headers,
   Map parms, Map files) {
 for (Map.Entry kv : parms.entrySet()) {
  String key = kv.getKey();
  String strValue = kv.getValue();
  if (key.compareTo("cmd") == 0) {
   startMeasurements();
   _callbackHandler.TA_PerformCommand(strValue);
   while (_inMeasurement) {
    try {
     Thread.sleep(1L, 0);
     long delta = System.currentTimeMillis() -
        _startTime;
     if (delta > 6000L) { // timeout after 6 sec
      addMeasurement("timeout");
      endMeasurements();
     }
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
   }
   String htmlResult = measurementsToHTML();
   return new NanoHTTPD.Response(Response.Status.OK,
       MIME_HTML, htmlResult);
  }
  else {
   Log.d("httpd", "Invalid param: " + key);
  }
  final String html = "Command Received";
  return new NanoHTTPD.Response(Response.Status.OK, MIME_HTML, html);
 }


The callback handler's TA_PerformCommand calls my server class endMeasurements once the operation is done setting the _inMeasurement flag to false.
If the action takes more than 6 seconds (a safe upper limit in my case), the loop times out and we end the measurement.

Once I have this little server set in my app, it is quite easy to write a testing script using JMeter, or a nice little app I found for my Mac: http://fakeapp.com/

It is now quite easy for me to repeat a sequence of tests, capture the times, tweak some of the code and test again.



Sunday, May 26, 2013

Analyzing SQLite on Android

Working on an Android project with quite a sophisticated SQLite DB, I am now trying to optimize the program access to the DB, and wanted to get access to the DB file. I don't like to root my devices (maybe I am over-sensitive about that), so I used this answer by RRTW from Stack Overflow (http://stackoverflow.com/questions/4452538/android-location-of-sqlite-database-on-the-device):


File f=new File("/data/data/your.app.package/databases/your_db.db3");
FileInputStream fis=null;
FileOutputStream fos=null;

try
{
  fis=new FileInputStream(f);
  fos=new FileOutputStream("/mnt/sdcard/db_dump.db");
  while(true)
  {
    int i=fis.read();
    if(i!=-1)
    {fos.write(i);}
    else
    {break;}
  }
  fos.flush();
  Toast.makeText(this, "DB dump OK", Toast.LENGTH_LONG).show();
}
catch(Exception e)
{
  e.printStackTrace();
  Toast.makeText(this, "DB dump ERROR", Toast.LENGTH_LONG).show();
}
finally
{
  try
  {
    fos.close();
    fis.close();
  }
  catch(IOException ioe)
  {}
}


So I can now grab the file with DDMS and examine it on my Mac.

Sunday, October 7, 2012

Arduino Adventures - part II

OK, I am stuck trying to transmit an IR code to turn my air condition on (see previous post here: http://srooltheknife.blogspot.co.il/2012/10/adventures-with-arduino.html). It is getting hot, and I want to turn the damn thing on...

So, next step is trying to debug what's wrong with my IR transmission. I decided that I need to somehow visually see how my signal looks and compare it to the (working) original remote control signal. So decided to hack a little Oscilloscope - hey, I already made a wave printing arduino sketch in the last round. If I can just measure the signal from the IR receiver using Arduino analog in pin, decode it and send it over the serial connection to the Mac, I can display it nicely on the screen. Ummm... interesting... a new sub-project.

First, had to get the serial connection between the mac and arduino working. The power of the internet and the cool people helped. Found this:
http://code.google.com/p/xcode-arduino-serial-communication/
thanks to Pat OKeefe (and in turn to Andreas Mayer's AMSerialPort).

Next was a simple Arduino sketch to measure and send the analog input from pin 1 using the fastest baud rate possible. Quite simple:

// The Arduino code.

#define ANALOG_IN 1

void setup() {
  Serial.begin(115200); // possible values: 9600, 14400, 19200, 28800, 38400, 57600, or 115200
  pinMode(ANALOG_IN, INPUT);
}

void loop() {
  int val = analogRead(ANALOG_IN);
  Serial.write( val & 0xff);
}


Using the Mac code on this github repo [https://github.com/iroth/simplearduinoscope] you select and connect the right serial port, and can see the signal on the screen. If you select the wait for trigger (or click the re-trigger button), the scope will freeze when a signal is detected so you can examine the signal.

I added a copy to ref button, so I can record the original remote signal, display it as a reference and compare to my transmission.
Here is a screen dump of the two signals. I am not sure why my signal is not affecting the air condition, they look quite similar, no?



The top white line is the signal from the original remote control, the bottom is from my IR transmitter.
Note that my little scope has a scale up and down buttons too - this helps. I am not sure how accurate my scope is, but the signals look quite similar. Still not working.

Well, at least I hope the digital scope projects helps someone. It is not very accurate, but can be useful for debugging the IR codes (note that the signal above is the decoded signal from the TSOP382 sensor, not the 38 kHz modulated signal which is way too fast for this scope). It can be useful for simple audio frequency examination (but still at the low range of the audio spectrum).
I will need a much faster processor, and probably a much faster communication link to get the samples fast enough to the computer to really make it a useful scope for a wider range of frequencies.