Another reason not to extend Application

At my day job, I've inherited an app that extends Application to hold a lot of heavy global state. The docs for the Application class explicitly say it can be used this way, and offer no stronger warning against it than to say it's usually unnecessary. A lot of developers do this, even when they acknowledge that global state is generally evil.

I recently discovered an obscure way this can bite you. I added a Service to my app and configured it to run in a separate process. Every Service exists within an Application, so if the service is running in a separate process from your app, it has its own instance of Application. But it's not necessarily an instance of the default Application; it's an instance of the Application of the app that owns the service. This caused my extended Application to be duplicated, creating all kinds of problems.

But it gets weirder, because the definition of "the app that owns the service" isn't always what you might think. The service I was using came from a library, so before I added it to my app, I wrote a little test app to see if it worked as expected. When I added the service to my main app, everything seemed to be working fine. But then I uninstalled my test app, and that's when my main app went crazy. Apparently, the "owner" of a service is the first app installed that exports it. So initially, the service was running as a component of the test app, using the default Application because the test app didn't extend it. But when I uninstalled the test app, my main app became the "owner" of the service, and the service started running with a copy of my app's ridiculously bloated Application. Boom!

I haven't experimented much with this yet, but I'm wondering if this wouldn't allow you to inject code and access the data of any "secure" app simply by installing an app containing a malicious version of a service that the target app uses before installing the target app itself. I guess it depends on exactly how Android decides whether a service exported by another app is the same service as the one being requested.