How to create content-provider across user profiles?

android, multi-user, service

Solution

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.

Problem

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)?

Original source