Awesome Android eXtreme Hacking. Part II. More sensors

Awesome Android eXtreme Hacking Part I HeaderAwesome Android eXtreme Hacking Part I Header


NOTE
This article has already been moved to the our new blog. Please update any link to this post as it will be removed in the future. This post is available clicking the link below:

http://papermint-designs.com/dmo-blog/2016-04-awesome-android-extreme-hacking--part-ii--more-sensors

Yes, we know. You had a very bad time waiting for this new AAXH issue. OK, sorry about that.... and do not worry, AWESOMENESS CONTINUES!. If you are reading this, you are probably following this awesome tutorial on how to badly hack into your phone. In that case you might had been wondering why some of your sensors were not producing data or why they just do it sometimes and some other times they don't.

I see, you were trying to use your accelerometer sensor to build some cool app and it didn't worked.. don't you?. Do not worry, you will find out soon how to deal with this.

The sort answer for not getting data from some of your sensors is that Android keeps them disabled. Not sure why this is done. Maybe to safe battery, maybe to avoid processing data when not needed... do not really know, but what is happening is that most of the sensors are disabled most of the time.

Android provides a hardware abstraction layer for many common sensors. Sensors that you can find in most of the phones and tablets out there: accelerometers, gyroscopes, light sensors, etc... This hardware abstraction is expose to you as an API that provides a common way to access those sensors, independently of the actual underlying hardware. In other words, you can use the provided API to access your accelerometers without knowing if they are connected through an I2C bus, a serial port or some complex proprietary interface).

This API is directly accessible from any Android Java application, however it is not part of the linux system and therefore it cannot be used directly from our small C applications. However, the sensors API is part of the NDK (do you remember?... the Native Development Kit), meaning that we can easily use them by linking to one of the general Android library.

Let's take a look to a very simple sensor access application

#include <stdio.h>
#include <unistd.h>
#include <android/sensor.h>
#include <android/looper.h>

ASensorEventQueue* sensorEventQueue;

static int get_sensor_events(int fd, int events, void* data);

int
main (int argc, char *argv[])
{
  ASensorEvent event;
  ASensorManager* sensorManager;
  const ASensor* accSensor;
   
  ALooper* looper = ALooper_forThread();
  
  if(looper == NULL)
    {
      looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
    }
  
  sensorManager = ASensorManager_getInstance();
  accSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);
  sensorEventQueue = ASensorManager_createEventQueue(sensorManager, looper, 0, 
						     NULL, NULL);
  ASensorEventQueue_enableSensor(sensorEventQueue, accSensor);

  while (1)
    {
      get_sensor_events (0, 0,NULL);
      sleep (1);
    }
}



static int fire = 1;

static int 
get_sensor_events(int fd, int events, void* data) 
{
  ASensorEvent event;

  while (ASensorEventQueue_getEvents(sensorEventQueue, &event, 1) > 0) 
    {
      if(event.type == ASENSOR_TYPE_ACCELEROMETER) 
	{
	      printf("(%04d) %+6.5f %+6.5f %+6.5f %lld\n", 
		     cnt, evebt,type,
		     event.acceleration.x, event.acceleration.y, event.acceleration.z, 
		     event.timestamp);
	}
    }
  //should return 1 to continue receiving callbacks, or 0 to unregister
  return 1;
}
So, what is this code doing?. The first thing that the code does is to create a looper. A looper is an Android mechanism to add a main loop to a running thread. We need this because the sensor infrastructure follows an event based approach. Whenever a new data is available, an event is created and pushed into a queue that the main application can then process to do whatever it has to do. Probably we could had avoid to use the looper, but it actually makes the code shorter and more compact. And we have to use the Android library anyway so... This may sound a bit strange but this is how most of the applications out there actually work. GUI or network applications are usually build like that, around a main loop that get asynchronous events and process them as they come. If you had ever wrote a GUI application using some low level APIs (Xlib or even the infamous Win32), the concept should loop familiar. You can read more about loopers here (http://developer.android.com/reference/android/os/Looper.html). Anyhow, in this case we are not actually attaching any handler to the looper. We want to process our events as fast as we can so, instead of calling the loop method on the loop object we actually run an infinite loop processing available events in our queues (we will come to those queue in a while)... which, at some extend is what the loop method actually does. So, now our application message loop is in place but we still have to initialise our sensors. This is done with the lines below the prepare call that we reproduce here for your convenience:
  sensorManager = ASensorManager_getInstance();
  accSensor = ASensorManager_getDefaultSensor(sensorManager, ASENSOR_TYPE_ACCELEROMETER);  
  sensorEventQueue = ASensorManager_createEventQueue(sensorManager, looper, 0, NULL, NULL);
  ASensorEventQueue_enableSensor(sensorEventQueue, accSensor);
The code is self-explanatory but just in case. We get access to the sensor manager instance (probably a singleton), and using it we get a handler for our accelerometer sensor. Then, we create a queue to get the vents from our sensorManager. The third parameter is an identifier for the events coming on this queue. We do not need it for our example, but basically it allows you to tag different kind of events on more complex applications. If you do not really understand what they are for, that probably means that you do not need them. The two last parameters allows as to define a function callback to process those events and some user defined data to be passed in the function. As we will be processing everything in an infinite loop we do not really need these parameters. In order to make use of those we should run our main loop using the looper object. Finally we enable the sensor and attach it to the just created queue. From this point on, the sensor is activated and we just go into an infinite loop calling a function that reads available events and process them. Now we just need to compile. We already know how to do this. The only difference now, is that we have to link to the android library, in order to use the sensorManager, the Loope, and the eventQueues. That is actually quite simple:
~/aaxh $ arm-linux-androideabi-gcc -o aaxh03 aaxh03.c -landroid
The program just dumps the accelerometers data to the console... So we can enjoy staring at those numbers. You know, one of those Matrix-moments. That might be hypnotic but not really interesting. For a more realistic example, change the get_sensor_events above for this new version:
static int 
get_sensor_events(int fd, int events, void* data) 
{
  ASensorEvent event;

  while (ASensorEventQueue_getEvents(sensorEventQueue, &event, 1) > 0) 
    {
      if(event.type == ASENSOR_TYPE_ACCELEROMETER) 
	{
	  printf("(%04d) %+6.5f %+6.5f %+6.5f %lld\n", 
		 cnt, event.acceleration.x, event.acceleration.y, event.acceleration.z, event.timestamp);
	  
	  if (event.acceleration.y > 0)
	    {
	      if (event.acceleration.y > 5 && fire)
		{
		  printf ("Volume UP!\n");
		  system ("input keyevent 24&");
		  fire = 0;
		}
	      
	      if (event.acceleration.y < 3) fire = 1;
	    }
	  else 
	    {
	      if (event.acceleration.y < -5 && fire)
		{
		  printf ("Volume DOWN!\n");
		  system ("input keyevent 25&");
		  fire = 0;
		}
	      if (event.acceleration.y > -3) fire = 1;
	    }	  
	}
    }

  return 1;
}
Yes, not as awesome as we are used to but... this small application reads the Y accelerometer value and uses it to change the volume on the device using the input keyevent command so simulate the press of the Volume Up/Volume Down buttons. OK, that is a bit awesome... isn't it? If you try the code, you will notice that it is not very reliable. It is just an example. For properly manage this kind of gestures you really have to take into account the timestamps and do some kind of data filtering, beyond the very basic hysteresis threshold we had used in the example. Now you can play with the rest of sensors in your phone... not sure how?. Take a look to the documentation (http://developer.android.com/guide/topics/sensors/sensors_overview.html). And remember to use the source Luke. Actually take a look under (/platforms/android-19/arch-arm/usr/include/android) on your NDK tree and look into the sensors.h file to figure out how to access data on other type of sensors. So this is it. This issue wasn't as awesome as usual. Sorry about that. We are not having too much time lately... but... come on, with all this information.... Awesomeness is in your hands!!! Happy hacking! Awesome Welles