Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create content-provider across user profiles?

For an embedded project building on the AOSP source, I have a big chunk of data in one (system) app that has to be accessible to other apps. Yes, I know: the typical job for a content provider or service, but ... the same data (same single instance of that big chunk) has to be accessible to apps ON ALL USER PROFILES on the device!

I already figured out that Android offers an android:singleUser="true" attribute for services, content-providers and receivers, but it has the annoying side-effect that it forces android:exported="false"! Hence I assume that one solution could be to have in my Manifest one content provider using android:singleUser="true" and a second one which is android:exported="true" and have that second just query the first for the actual data that the other app might need, but ... that seems so ugly and in my case - where the app with content-providers and services already exists for single-user Android, it will require quite some changes.

I also tried flagging my complete (system) application as android:persistent="true", but this resulted in problems accessing some parts of /data/data where the big chunk of data resides (which I need to debug further to get to the root cause).

So, my question: is there any easy / advised way to create a content-provider (and same question for services and receivers in the same app) such that the app really acts as a singleton across multiple users (without being a System Service, since we don't want to affect system stability by running our stuff as part of the SystemServer)?

like image 333
Mr.K Avatar asked Jan 07 '14 08:01

Mr.K


People also ask

How many content resolvers can an app have?

You can implement as many as you want, as you can see from the documentation here. To register a content provider, you need to add its corresponding <provider> tag in the Android Manifest. In most cases, however, you won't need multiple content providers. One is usually enough, as it can handle multiple tables.


Video Answer


2 Answers

Using android:singleUser="true" with android:exported="true" is the right way to go, but there are some caveats to using this attribute.

First, ActivityManagerService (isSingleton method) will ignore this attribute unless your app has the INTERACT_ACCROSS_USERS permission.

Second (and this is where I think your problem is), your app must also be installed as a privileged app in the priv-app folder ('LOCAL_PRIVILEGED_MODULE := true' in Android.mk). Otherwise, the PackageParser will clear your 'android:exported' attribute.

 if (sa.getBoolean(
        com.android.internal.R.styleable.AndroidManifestProvider_singleUser,
        false)) {
    p.info.flags |= ProviderInfo.FLAG_SINGLE_USER;
    if (p.info.exported && (flags & PARSE_IS_PRIVILEGED) == 0) {
        Slog.w(TAG, "Provider exported request ignored due to singleUser: " 
                + p.className + " at " + mArchiveSourcePath + " " 
                + parser.getPositionDescription());
        p.info.exported = false;
    }
}

NOTE: All of the above applies not just to Providers, but Services and Receivers as well.


UPDATE: It looks like the test for the package being a privileged app is only present in Android 5.0 and later. Earlier versions simply dropped the export attribute.

like image 129
James Puderer Avatar answered Oct 23 '22 02:10

James Puderer


Have an exported="true" service that accesses the singleUser="true" content provider.

like image 1
Jeremy Stein Avatar answered Oct 23 '22 03:10

Jeremy Stein