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)?
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.
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.
Have an exported="true" service that accesses the singleUser="true" content provider.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With