Friday, 25 October 2013

How to get a context from everywhere

As an Android developer and also a Cydia user you may have noticed you ALWAYS need a context. That is a complication in Android design (I may say, a poor software design but I'm not here to argue about it) that makes us pass the context from everywhere to everywhere else to make things work as expected.
For example, if you need to use a database, you will need a context to instantiate a helper to manage its creation and version management. But what if you need to query your own data base but you are in the middle of your hooked method? You may have realised you're actually running in the hooked process environment, so you cannot assume you have a view or an activity or that extra permission you need. You don't even have access to some files you had in your own application's environment. You are on your own in someone else's zone.

That's why we struggled to figure out how to get a context from nowhere with no assumptions using some of the feature Saurik gave us, but what our java reflexion old friend gave us, too.

Our first method uses java reflexion and the knowledge that we can get a context for almost* everywhere calling ActivityThread.currentActivityThread().getSystemContext();

In order to do that, just add this code to yours: code.
* with "almost" I mean you won't have an activity thread when your device starts up and that's a pity because most of us want the hook to work all the time, even when there's no activity displaying.

Our second method hooks some context method we are pretty sure will be called by the hooked application so we save the context and return the call's expected result. Fill free to change the method used in our example to your taste.
To make this second approach work, we are based in the fact that every application has it's own copy of the libraries it uses in runtime. That let us guarantee the context is a valid one for the application we are willing to hook :)
In our example, we used the method Context>>getSystemService(String) which we are sure will be use to get one of the several services you can access making this call, such as bluetooth, telephony, location, wifi, among others.
To make it clearer, you can, for example, get the current WifiManager as follows:
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);

In order to do that, add this hook to your main hook: code.

And that's basically it! Just try these twe example and let us know if you have any trouble making them work.
I'm batdroid