How to query a ContentProvider in another profile? - android

I am trying to determine how to access a ContentProvider which exists in another profile.
I have an app/service in the managed profile which implements a content provider.
I have a 2nd app/service in the primary profile and I want it to be able to access the managed app's content provider. i.e. cross-profile
Right now I am prototyping the implementation using a modified version of android-testdpc. I have added a ContentProvider to the testdpc source. I want to be able to access this ContentProvider, which is in the managed profile, from another app that is running in the primary profile.
I know that using DevicePolicyManager.AddCrossProfileIntentFilter() I can allow intents sent in the managed profile to also be resolved in the parent, or vice versa. The documentation states that only activity intents are supported. Using AddCrossProfileIntentFilter() I have successfully been able to pass data between the two apps by using intents and startActivity().
However, using activities is not what I want to do since in Q and later I cannot start an activity from a background app/service.
I have no problem accessing the ContentProvider if the two apps exists in the same profile but I have been unable to determine how to make this work cross-profile.

I finally got this working.
To do so I needed to use an activity in the content provider to give permission to the other app. The non-content provider app must send an intent to an activity in the content provider app, requesting permission to access the content provider, using startActivityForResult().
This activity returns an intent, setting the content provider URI with Intent.setData() and permissions with Intent.setFlags(). In my case I included Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION to make the permission persistent.
The non-content provider app gets the result intent in onActivityResult(), gets the URI from the result then calls ContentResolver.takePersistableUriPermission().
To make this work cross-profile I used DevicePolicyManager.addCrossProfileIntentFilter() to allow the permission request intent to cross profiles. When crossing profiles I noticed that the content provider URI returned in the result intent include the user id. i.e. “content://10#com.example.myprovider/test". Making a query using this URI will cross profiles.
This helped https://www.futurelearn.com/courses/secure-android-app-development/0/steps/21592

Related

Android: how to restrict access to ContentProvider

Is it possible to add a filter to a content provider to make it accept only requests coming from a set of known application IDs?
For example, if com.domain1.app1 and com.domain2.app2 are two app that I trust I'd like to make them read my data. Any other application should be kept outside.
Something like intent filter but related to incoming request from other applications.
I know about the same signing key but it's not what I need.
If a provider's application doesn't specify any permissions, then other applications have no access to the provider's data. However, components in the provider's application always have full read and write access, regardless of the specified permissions.
As seen here.

Android: Directory data provider for PhoneLookup

I'm writing a custom Android contacts directory, I have implemented the ContactsContract.Directory provider and the search from within the phone app works fine.
The problem I am facing now is that when I have an incoming/outgoing call the Android dialer does not query the custom directory I registered. Is it possible to partake in caller ID resolution via PhoneLookup or some other way?
Also as a possible workaround I have tried implementing an outgoing/incoming call interceptor with BroadcastReceiver but I see no way of returning the contact data to the dialer. The only option I have found for displaying the data is to overlay a transparent activity over the native dialer. Is there a way to return contact data back to the dialer that sent the broadcast? Any other ideas I could try?
PS. Google uses the functionality I'm trying to implement for nearby places directory listings and Caller ID by Google.
PPS. By reading the ContactsContract implementation of PhoneLookup I stumbled upon corporate contacts directory that can be appended to the user profile's default directory, according to the code it should get queried for PhoneLookup, so I'm going to try that on Monday.

Sharing String between two applications

I have two applications and I want to be able to share a String value between them. For example: user changes the String in app A, when app B is launched, I want it to read the updated String (and vice versa).
I was trying to use SharedPreferences with Context.MODE_WORLD_WRITABLE, but it's been deprecated.
How can I achieve this?
EDIT: App A has to save the value without launching app B. App B has to be able to read that value without launching app A.
I looked at ContentProviders, but they look too complex, especially for a simple String sharing.
One option is use webserver for this. for example store value in web server from app1 and access this value from app2
option two is use content providers. Through the content provider, other apps can query or even modify the data (if the content provider allows it)
Simply put:
one application needs to send intent with data
the other one needs to listen for it with brodcast receiver.
Content provider is probably not the thing you are looking for.
here is good tutorial for brodcast receiver
Try http://developer.android.com/training/sharing/send.html or http://developer.android.com/guide/topics/providers/content-providers.html to share data between 2 applications

How to grant permissions only to the creator of an URI

I have an application, say ApplicationProvider, which holds a provider and a receiver.
Another application, say ApplicationCreator, creates an element on the provider through an intent. The ApplicationProvider get the intent and creates the element accordingly.
Now I would like ApplicationCreator to be the only one to hold the rights to access that element. So if another application tries to access that element, this generates some kind of error.
What is the best way to do so? I came up with two possible solutions, but I don't like any of them.
1) ApplicationProvider denies any direct access to the provider, instead uses the receiver to get the intents which are sent through intentForResult, so the receiver can check the caller, verify that is the original caller who created the element and grant access. Other applications would get denied because they hold a different uid. Since there is no easy way to forge the uid, this system works.
2) Any application can send intents to the provider but in the manifest i specify all the path-level permission to the single uris that are created. I manually issue an update to the application every time someone wants so create a new element.
=========================================
Additional information:
It would be ideal if different applications could put different elements and be able to retain the rights to modify those elements they created and also grant permission on those elements to whom requested said permission.
A---> +--------+ A creates content
| pro | <---B B asks permission
A<----| vid | the provider forward permission
A---->| er | A grant permission
| | --->B B is given permission and can access A's stuff
+--------+
Here are my thoughts on this topic. No code is provided, since I did not implement anything. Also, I'm not entirely sure that this solution is entirely secure.
First, authentication.
Every client who wants to use your content provider needs a key. Each client fetches one key from your application (maybe implement a content provider for that). A random sequence of letters / numbers should be fine. This key is stored within your application and the clients application, somewhere where noone else has access, i.e. a private database / preference property.
This key is used to authenticate a client application with your content provider. On each request, this key (maybe a hash of the key) is included within the request uri (much like API keys when using REST web services). Your application checks whether the provided key was previously generated. If that is the case, authentication is successful.
Next, authorization.
Each element in your database has a field ownerKey. When creating new elements, this field is filled with the key provided with the request. When accessing / modifying / deleting elements, your content provider should check whether the stored key matches the submitted key. Only perform the operation if the keys match.
Additional thoughts.
The whole point is that the random keys generated by your application stay private. I'm not sure whether it is possible for a third party to intercept interaction between a client application and a content provider. You might want to investigate this before writing any code.
Specifying a key on each request could be optional. When omitting a key during element creation, those elements do not have an ownerKey and thus are allowed to be accessed and modified by anyone without authentication/authorization.
I hope this helps somewhat.
I would suggest the uid approach, but there is no reason for this to go indirectly through a receiver. Just store the owning uid for each row in your database, and on incoming calls to the content provider use Binder.getCallingUid() to retrieve the uid of the current caller which you can validate against the row they are operating on.

Can multiple ContentProvider's serve the same URI?

When querying a ContentProvider on Android, one specifies the ContentProvider of interest by providing the "content URI" for that ContentProvider. What happens when multiple ContentProvider's serve that same URI, either intentionally? or maliciously?
When trying to open a pic on my phone, I've seen it prompt with apps that can "handle" the image. Will the same kind of thing happen here?
Multiple ContentProviders can't do this. The first application that registers a content provider using the element in its manifest has control over the URI pattern. I'm pretty sure that you'll get an installation error if you try to add another provider that uses the same URI pattern. Android keeps track of providers and URIs.
When you see a prompt with multiple apps for handling a file or situation, that's because the apps have specified an with a child that includes
android.intent.category.CATEGORY_ALTERNATIVE or android.intent-category.CATEGORY_SELECTED_ALTERNATVE. In essence, the app or apps are declaring themselves to be alternatives to the action specified in the child. This allows the user to have multiple choices for handling a type of data.
It makes sense to provide alternatives: a user might want to edit a picture, share it via Twitter, or e-mail it.
Note that two content providers can do the same thing, but they can't use the same URI. An app has to make a conscious choice of which one to use, or provide some mechanism of choosing between the two.

Categories

Resources