Android Bug/Architectural Issue: How do I handle multiple versions of my own Content Provider?

27 views
Skip to first unread message

whitemice

unread,
Jan 8, 2009, 10:19:04 AM1/8/09
to android-platform
I’ve blogged this question with pictures here:
http://tinyurl.com/9hwdva

I am writing a component that makes certain functionality available to
any application running on an Android device (e.g. an advertising
service, stock ticker cache, Snowball server, etc).

This functionality is useful for application developers, but not
interesting to actual users i.e. my component should be included as
part of a new application, but not require the end user to explicitly
install the additional component themselves.

I expect that over time multiple applications installed on the phone
will want to communicate with my component. As each new application
will have a different certificate, I want to communicate between
applications using an Android Content Provider. To save resources on
the device (networking, caching, etc) only one instance of my
component should be appointed to handle all queries.

This works well as Android only registers the first Content Provider
for a given URI and then ignores the rest (throwing an “WARN/
PackageManager: Skipping provider name xxxx name already used” error
each time a new one is installed).

However if the registered Content Provider is uninstalled, it will
immediately break all the other applications that rely on it, even
though other instances of the component still exist.

Questions:
- Does anyone have any suggestions on how to better handle this
situation?
- If I could reregister Content Providers I could handle situations
like this, and upgrade components when newer versions are installed.
Perhaps the Android OS could also handle this situation better, by
tracking Content Provider naming collisions?
- Should I be looking at other communication methods to solve this
issue?

Muthu Ramadoss

unread,
Jan 8, 2009, 10:45:59 AM1/8/09
to android-...@googlegroups.com

whitemice

unread,
Jan 8, 2009, 12:49:14 PM1/8/09
to android-platform
Hi Muthu
Thanks for the response.

It seems the attribute “android:multiprocess” in the “provider” tag
seems to have a behaviour that is not relevant to this problem, i.e.
it prevents multiple instances of the same Content Provider from
existing, rather than affecting multiple Content Providers trying to
use the same namespace.

Also, having it set to either true or false didn’t affect the outcome
of my tests.

I’ve only limited experience of Android inter-process communication,
and would be grateful if someone could shed some light on this issue.

Regards
Mark


On Jan 8, 4:45 pm, "Muthu Ramadoss" <muthu.ramad...@gmail.com> wrote:
> Have you tried setting
> android:multiprocess<http://code.google.com/android/reference/android/R.styleable.html#And...>
>
> as defined here:
>
> http://code.google.com/android/reference/android/R.styleable.html#And...
>
> ?
>
> take care,
> Muthu Ramadoss.
>
> http://linkedin.com/in/tellibitz+91-9840348914http://mobeegal.in- mobile search. redefined.

Muthu Ramadoss

unread,
Jan 9, 2009, 12:20:28 AM1/9/09
to android-...@googlegroups.com
Mark,

AFAIK, a Content Provider is tied up to a unique Authority.

If you want to support multiple URI's you do so accordingly by providing different URI paths using the same authority.


Here is a recap of the important parts of a content URI:

Elements of a content URI

  1. Standard required prefix. Never modified.
  2. Authority part. For third-party applications, this should be a fully-qualified class to ensure uniqueness. This corresponds to the value in the <provider> element's authorities attribute: <provider class="TransportationProvider" authorities="com.example.transportationprovider" />
  3. The path that the content provider uses to determine what kind of data is being requested. This can be zero or more segments: if the content provider exposes only one type of data (only trains, for example), this can be absent. If it provides several types, including subtypes, this can be several elements long: e.g., "land/bus, land/train, sea/ship, and sea/submarine" to give four possibilities.
  4. A specific record being requested, if any. This is the _id value of a specific record being requested. If all records of a specific type are being requested, omit this and the trailing slash: content://com.example.transportationprovider/trains

http://code.google.com/android/devel/data/contentproviders.html

take care,
Muthu Ramadoss.

http://linkedin.com/in/tellibitz +91-9840348914
http://mobeegal.in - mobile search. redefined.

Mike Hearn

unread,
Jan 9, 2009, 3:53:11 AM1/9/09
to android-platform
This is a wider issue than just content providers, consider a library
that exports some non-trivial Activity (such that you don't want to
copy/paste it into each app). I don't think there is any solution for
versioning of Intent protocols today, or at least I didn't see one.

For what it's worth, MacOS X uses a similar versioning scheme to what
you propose - if it finds multiple copies of a library included inside
app packages, it'll use whichever is the latest version, so you get
both memory efficiency and ease of distribution. It's more network/
disk heavy, but the complexity reduction over a full dependency solver
is easily worth it.

I think Android could do worse than copying this approach. Right now
the approach seems to be asking the user to manually install separate
packages from the Market, there's even a software libraries category.

Muthu Ramadoss

unread,
Jan 9, 2009, 4:01:15 AM1/9/09
to android-...@googlegroups.com
The Android approach right now is to bundle the components as an apk and then use the apk install/upgrade/remove mechanism respectively to install/upgrade/remove components.


take care,
Muthu Ramadoss.

http://linkedin.com/in/tellibitz +91-9840348914
http://mobeegal.in - mobile search. redefined.



whitemice

unread,
Jan 9, 2009, 4:54:58 AM1/9/09
to android-platform
Thanks everyone for the replies:

Just to clarify: I am writing an advertising server component at the
moment, but other projects that I have in the pipeline essentially
have the same requirement.

>>Dianne Hackborn - As far as naming issues, this is why you should use an authority in a
namespace/domain you own, so that there will not be naming
collisions.<<
My application sits in its own namespace. I am only having conflicts
with different copies of the same Content Provider Component being
installed with different applications.


>>Dianne Hackborn - …any client app that is relying on a component that is not part of the base platform needs to deal with the error cases if that component does not exist.<<
If the component is not there, then the application would show an
error on start and normally refuse to run. Result: Bad user
experience.


>>Peli - Hm, I think you end up with unnecessary code duplication if you include your component / content provider in every application.<<
This isn’t an issue, as my component is delivered as a small Java
class included with the main application. When activated, the
component inflates in size as it downloads content over the internet.
My goal is to manage this process by having only one component
activated regardless of how many applications are installed on the
device.


>>Peli - I think it would be better if every application that wants to use your component shows a small dialog "You need to install the following component..." with a button that brings you to the download page of the Market for your component...<<
Catching a missing component is easy enough. It’s just that what you
describe adds up to a bad user experience:
- No user will download a 3rd party advertising server (or any non-
core functionality) just to run a game.
- Installation is already a convoluted process and should only take
place once. Additional APK installations require more downloading,
application permission settings, button pressing, confusion, etc.
- No client of mine will accept a solution that asks the user to jump
through any additional hoops (e.g. even the Android Developer
Challenge only permitted a single executable).


>>Peli - At OpenIntents we try to resolve dependencies as late as possible - i.e. not at installation time, but the first time the user actually wants to use a particular feature (they may never use it in which case there is no need to install it).<<
This doesn’t work for me as ad funded Applications generally require
my component to be available on startup.


>>Peli - I think in the long run Market should have better tools for resolving compulsory dependencies automatically, but for the moment I think this is a good compromise for developers and end users.<<
I agree that this needs to be improved, as there is currently no
support for components (downloading, versioning, upgrading, etc) in
Android or on the Android Market. Hence I am trying to get around
this issue by “managing” a Content Provider.

>>Dianne Hackborn - Oh wait if what is being talked about is having the same content provider in multiple applications, that is completely the wrong approach. For a given authority there must be one and only one content provider implementation, living in a single specific .apk.<<
This is how it’s done at the moment, i.e. Android will log a warning
(and do nothing) every time an application tries to register a Content
Provider URI that’s already in use. This means that subsequent
applications will be broken (and need to be reinstalled) if the
original Content Provider is ever uninstalled. I don’t seem to be
able to reregister a missing Content Provider URI at runtime.


>>Muthu Ramadoss - AFAIK, a Content Provider is tied up to a unique Authority. If you want to support multiple URI's you do so accordingly by providing different URI paths using the same authority.<<
I explored this approach initially, but it still has the following
problem:

Over time, I release a number of versions of my component that other
developers subsequently integrate into their own applications. My
component uses the following URI conventions:
content://mynamespace.mycomponentnamespace.version1/
content://mynamespace.mycomponentnamespace.version2/
content://mynamespace.mycomponentnamespace.version3/

Android allows me to search and interrogate each URI to check the
status of each Content Provider (allowing me to version my
component). This is fine until v3 of my component becomes really
popular and a user installs five games on their phone, each with the
same component trying to register the same URI.

The user then gets bored of the first game and uninstalls it, thereby
breaking all the other games that rely on the Content Provider that it
contains. As URIs are set at install time, none of the other games
will work until the user reinstalls an existing game or downloads a
new one - This is a terrible user experience.

Regards
Mark

Dianne Hackborn

unread,
Jan 9, 2009, 3:51:10 PM1/9/09
to android-...@googlegroups.com
But fundamentally, activities are not shared libraries.  An activity is something that knows how to operate on an Intent for the user.  If you try to call startActivity() with an Intent for which there are multiple possible activities that can handle it, then the user will be prompted with a dialog to decide what they actually want to do at that point.  There is no versioning here, there is the question "which specific type of operation were you interested in doing?".

Managing dependencies is another issue, but at the Activity level these are not versioning dependencies, these are feature dependencies.  For example, there is a radar activity on the market, and someone else could write an app that allows you to invoke a radar view from it.  It would be nice for it to declare in its manifest that it needs a radar activity, so the Market could have the user pick an app with a radar activity (other people could write alternative types of radars, again not "clearly better than" newer versions) when downloading the original app.

Or we have also talked about, when actually invoking the radar activity, having the system present a UI to find and download an app that does that at the point it is needed.  This seems pretty reasonable because also unlike libraries, activities are a fundamental part of user flow, so interacting with the user to resolve dependencies at the point of use would seems fairly viable.
--
Dianne Hackborn
Android framework engineer
hac...@android.com

Note: please don't send private questions to me, as I don't have time to provide private support.  All such questions should be posted on public forums, where I and others can see and answer them.

Mike Hearn

unread,
Jan 9, 2009, 5:01:17 PM1/9/09
to android-platform

> Or we have also talked about, when actually invoking the radar activity,
> having the system present a UI to find and download an app that does that at
> the point it is needed. This seems pretty reasonable because also unlike
> libraries, activities are a fundamental part of user flow, so interacting
> with the user to resolve dependencies at the point of use would seems fairly
> viable.

Yes, that approach sounds reasonable. Although the Market UI paradigm
is pretty limited - if I click a button and the OS asks me to pick one
of three radar views, it might be hard for me to figure out which one
I want. They're all radars right? How fancy can it get?

They could be sorted in order of star rating, or show user comments
etc, but then I'm being distracted from what I actually want to do
with a choice that might be (in the larger scheme of things)
irrelevant.

Perhaps then a middle path - the author of an activity can fire an
intent with a recommended package name which is automatically fetched
if no suitable activity is installed, but the user can still see a
list of available alternatives in the manage applications view, and of
course the app could open that alternatives picker activity from its
settings menu or whatever.

Muthu Ramadoss

unread,
Jan 10, 2009, 12:01:06 AM1/10/09
to android-...@googlegroups.com
"The federation of loosely coupled components" philosophy of Android design seems to give a lot of power to Users (which is cool!) to configure their applications in a powerful way. Whatever would make it more easier for User like providing ratings, preferred and recommended Components is a definite plus.

To add more on the radar discussion:

If the User had already selected a radar as his default, it would be nice if the platform has the ability to list all available components again that can handle this particular action on a request basis. I'm not sure if the User is given the choice again after he had selected a component as his default.http://androidrocks.in - Android Consulting.

Dianne Hackborn

unread,
Jan 10, 2009, 12:30:13 AM1/10/09
to android-...@googlegroups.com
On Fri, Jan 9, 2009 at 9:01 PM, Muthu Ramadoss <muthu.r...@gmail.com> wrote:
If the User had already selected a radar as his default, it would be nice if the platform has the ability to list all available components again that can handle this particular action on a request basis. I'm not sure if the User is given the choice again after he had selected a component as his default.

Normally after selecting a default you won't be asked again for that particular intent, since that is the point of selecting a default.  If you want to reselect, you need to go to manage applications and remove defaults for that app.  That's unfortunately very not discoverable, it is true.

whitemice

unread,
Jan 15, 2009, 8:06:39 AM1/15/09
to android-platform
Solution
The simplest solution (not using intents) is to instruct each user of
my component to define a new content provider:

content://myComponentNamespace.theirApplicaitonNamespace

Android lets me search through all available content providers, which
can be string matched to my own component namespace.

context.getPackageManager().queryContentProviders(null, 0, 0);

If I find more than one valid Content Provider I can then pass around
Synchronisation information (validity, compatibility, version, status,
etc) using any of the ContentProvider class methods (I used getType
()).

The only problem with this approach is that the application developer
who imports my component (as a JAR) will have to define their own
custom Content Provider. This is done by extending the
MyComponentContentProvider class (from my JAR) and defining a
CONTENT_URI variable.

package test;
import com.whitemice.MyComponentContentProvider;
public class TheirContentProvider extends MyComponentContentProvider {
public static final Uri CONTENT_URI =
Uri.parse( "content://
myComponentNamespace.theirApplicaitonNamespace");
}

As well as adding the custom provider to the Android manifest.

<provider
android:name="test.TheirContentProvider"

android:authorities="test.service.TestContentProvider.TestAndroidContentProvider"
/>

Without the custom Content Provider configuration, Android will behave
strangely and sometimes call a different .APK file if it has a class
in it with the same name.

As this is a work time project, I will have to check if I can release
the synchronisation code as a working example. If I do it will appear
on my blog here:
http://tinyurl.com/9hwdva

Regards
Mark

P.S. Thanks again everyone for your suggestions.
Reply all
Reply to author
Forward
0 new messages