Multiple write from multiple process in Android Content provider - android

I know Android's ContentProvider is known for multiple write from multi-process/multi-thread without throwing lock exception. In multithreaded environment it might have synchronized the method using read-write lock. But what about multi process where multiple object will be created. Can any one let me internal working of ContenProvider.

A ContentProvider is a manifest declared component, it is instantiated by the OS and is tied to the main process (unless the attribute process is specified differently). Therefore only a single instance of a declared ContentProvider is created during the life time of that application process. Other processes that wish to interact with it must go through the ContentResolver which in turn just communicate with that single provider created.
Note that when a provider is used from another process it is communicating via IPC (via Binders specifically), which means a provider's methods will be invoked in a BinderThread during an IPC call. There is a pool of binder threads so that there can be some concurrent communication with multiple application, meaning appropriate synchronization should be done.
In summary, content providers are safe for multi-process & multi-thread interactions because:
They are a Singleton.
Multi-thread safety is guarantee by the developer with appropriate synchronization of shared state.
Multi-process safety is guarantee by the ContentProvider.
The ContentProvider's definition has return types that are suitable for IPC interaction. (They are Parcelable, like AssetFileDescriptor, or they are a SQLiteCursor which is backed by allocated shared memory using ashmem).

Related

Why Binders(used for IPC) even when activity and services are in the same process

Binders are used for Inter(not intra) Process Communication/Remote Method Invocation so why/how the communication between Activity and Service is possible via binders where there are no different processes involvement.
When the very first component of an app is initialized a request to the kernal is triggeres (I think via ActivityManagerService(Native)-AMS > AMN) (running in system_process) for a new process fork if no corresponding process exists. Once the process is created then any other component (say a Service) belongs to the same process unless specified. Now this service wants to communicate to an Activity of the same process. Then why IBinder is one of the option?
Doesn't that violate the underlying principle on which Binders are created?
Interprocess communication is done by writing data to some source such as a socket or pipe, and another process reading it. There's no reason that the same process can't read and write though- it's less efficient than other means of passing data within a process, but it still works.
As for why would you use it in the same process- the alternative would be for Android to have two ways of communicating with services, one way for if they're the same process, and one way for it they aren't. That would complicate things for the framework for minimal gain. It would greatly complicate things for Services where the client may or may not be in the same process (say a service that is used by both the client app and other apps by the same company). So they just use the same method for both.
Binders are intended to be a construct of an IPC - this is true but, if used in the same process to communicate between an Activity and a Service, there is no performance cost, i.e, it is converted into a direct call instead of an RPC.
Don't assume that Binders will only be used for IPC but it is a general purpose communication mechanism in Android.
You won't find this documented normally anywhere. I found it in one of the discussion between Commonsware and Dianne Hackborne(designer of the binder concept in the Android team).

What is the downside if using ContentProvider within the same process

I am wondering if there'll be an extra cost to query the content provider within the same process. I'm aware that the Content Provider is transacting data by the binder, and all the data transition between binder service and binder client will be passing by binder driver in kernel space.
I suspect if it still uses the same approach while we use the content provider in the same process and therefore causes extra overhead such as latency, extra computing...etc.
Here's the scenario - in the multi-process app, you will normally require your storage system to use the binder system to pass data between processes, but at the same time, you will also need to pass data within the same process.
What's the common approach if you have a multiprocess android app? For now, I know a third-party solution MMKV but I am not sure if there's an official solution to avoid this kind of overhead (if it even exists).
I am wondering if there'll be extra cost to query content provider within the same process
There definitely will be overhead incurred by using ContentProvider, compared with simply calling methods on an object. Inter-process communication (IPC) is not free. This is one of the reasons for the complaints about performance of the Storage Access Framework, which relies heavily on ContentProvider.
The fact that the ContentProvider is in the same process as the consumer should not eliminate this overhead.

Shared data and multi-threading in Android

I would like to add a SyncAdapter to my app to update server-side data with minimal battery-use. For this, I need to have my application's main activity write data to some shared storage location that the SyncAdapter can then read in the onPerformSync(...) method.
I'm trying to figure out where best to store this data and have the following questions:
Could the SyncAdapter ever be called in a background thread while my main activity is executing in the foreground thread? I.e. do I need to worry about thread-safety of my storage access between the SyncAdapter and my main activity?
Are there ever any situations in which two instances of my main activity could be in the "Created" state? I.e. do I need to worry about thread-safety between two instances of my main activity?
Assuming that I do have to worry about any sort of thread safety, I have the following questions about the different data storage options:
Files in internal storage:
Are there any atomic operations I can perform on files in internal storage?
How about file locks?
SharedPreferences:
If two editors in different threads simultaneously modify different!!! keys in the Shared-Preferences, could two simultaneous commits lead to the loss of one of the changes?
SQL database:
Is the Android SQL Lite framework thread-safe if I simultaneously open the same SQL Lite database file from different threads?
Are there other ways to share data among SyncAdapters and (multiple instances of (if that is even possible)) the main activity?
Aside: To maximize compatibility of my app, I would like to not use any APIs greater than level 5.
I think, it should be possible to fix this issue by using a ContentProvider.
ContentProviders don't inherently solve the multithreading issue, as stated in the documentation:
Data access methods (such as insert(Uri, ContentValues) and update(Uri, ContentValues, String, String[])) may be called from many threads at once, and must be thread-safe. Other methods (such as onCreate()) are only called from the application main thread, and must avoid performing lengthy operations. See the method descriptions for their expected thread behavior.
But, unless the ContentProvider is declared with android:multiprocess=true, there should only ever be a single instance of the ContentProvider (if I understand this correctly), or at least all instances will live in the same process, i.e. they should have access the same static fields in the class definition.
With this, it should be possible to use the standard Java synchronization features to manage access to the storage-backed resources.
Please comment if I'm missing something...
Aside: Why all the "should's"?
Because, unfortunately, with Android's documentation, I'm never 100% sure that it's reliable or complete. Example here: The quote above states that "[o]ther methods (such as onCreate()) are only called from the application main thread"... What happens when I set android:multiprocess=true? The docs there state that "if this flag is set to 'true', the system can create an instance in every process where there's a client that wants to interact with it". Would this lead to a call to onCreate() from a thread other than this application's main thread? Probably...

Advantages of using Binder for IPC in Android

What is the advantage of using Binder for IPC over (Semaphores , Message Queue, PIPES) in Android stack?
Old question (and likely unmonitored by the poster), but worth answering:
A) All filesystem-based or filesystem-representable IPC mechanisms (notably pipes), can't be used because of a lack of a world-writable directory, where all processes can mkfifo/create the filesystem/socket representation of their IPC port (/dev/socket notwithstanding, which is used for system processes, e.g. rile, zygote, and their ilk).
B) None of the suggested mechanisms have the capability of "service location" which is required for Android. In UNIX, there's an RPC portmapper, and Android needs similar functionality. Enter: The ServiceManager, which can use binder to register as a context manager, to register/lookup service handles on the fly
C) There is an extensive need for serialization - be it intents, or other messages. Binder provides the parcel abstraction, which can be used for data marshaling by the Parcel.java.
D) SysV has other issues than Mr. Lambada's answer which are more paramount, notably race conditions, and lack of authorization.
E) Message queues and pipes can't pass descriptors. UNIX Domain sockets may, but can't be used because of (A) (again, unless you're root/system, like zygote, rild, installd..)
F) Binder is really lightweight, and has built-in authorization mechanisms. It also has nifty features like waking up the recipient process, as well as memory sharing, which the other mechanisms simply don't have. (and remember, no mmap(2), because of the file problem in (A) for named mappings).
and - let's not forget
G) Binder was started at Palm (ah, nostalgia) (q.v. OpenBinder). Ex-palmers got to Android, and brought their code in with them.
From the ndk's docs/system/libc/SYSV-IPC.html file:
Android does not support System V IPCs, i.e. the facilities provided by the following standard Posix headers:
<sys/sem.h> /* SysV semaphores */
<sys/shm.h> /* SysV shared memory segments */
<sys/msg.h> /* SysV message queues */
<sys/ipc.h> /* General IPC definitions */
The reason for this is due to the fact that, by design, they lead to global kernel resource leakage.
For example, there is no way to automatically release a SysV semaphore allocated in the kernel when:
a buggy or malicious process exits
a non-buggy and non-malicious process crashes or is explicitly killed.
Killing processes automatically to make room for new ones is an important part of Android's application lifecycle implementation. This means
that, even assuming only non-buggy and non-malicious code, it is very likely that over time, the kernel global tables used to implement SysV IPCs will fill
up.
At that point, strange failures are likely to occur and prevent programs that use them to run properly until the next reboot of the system.
Binders are used to to communicate over process boundaries since different processes don't share a common VM context => no more direct access to each others Objects (memory). Both parties within the same process (usually things that are within the same app) means (imho) that you should not use Binders since they slow down / complexify things unnecessary.
Binders are usually not used directly but rather via the "Service" or the "Messenger" classes. While communication with a Service is done via a full api of functions, the communication with a Messenger has to use "Message"s. Messengers a lot simpler to implement.
Apart from using Binders you can use anything that is available from any VM instance like "LocalSocket"s, Files, ContentProviders, Intents, ...
Binders are not ideal for transferring large data streams (like audio/video) since every object has to be converted to (and back from) a Parcel. All the conversion takes time. Much better in that case would be a LocalSocket for example.
Binders are used to enable remote procedure calls. You could implement RPC using the synchronization tools you mention but you would also need to write a lot of code to make it come together... with a Binder (normally only used within an Android Service) you have much less code to write; barely more than your actual remote functions.

Android binder security

Is the interprocess communication provided by Binder in Android protected against man in the middle attacks? Is there any documentation that provides this info?
Binder uses a capability-based security model. Each binder object represents a capability; handing that object to another process grants the process access to that capability. From that perspective, you prevent man in the middle attacks by not handing an important binder object to the man in the middle. If a process doesn't get handed a binder object, it can not access it in any way.
Regarding the "cross-binder reference forgery" issue discussed in the paper, if I am understanding the specific scenario they are talking about, I think their addendum about user space is a little weaker than I would agree with. They make the mistake I think of looking at the special C code written for the ServiceManager. Formally, I would consider the C++ user space code (consisting in particular of Parcel) as being part of the Binder architecture. This code in particular makes sure to deal with such attempts at spoofing when you call its readBinder() and related methods.
I don't agree with the statement that it is a flaw that the kernel is not completely ensuring integrity of the data. The only way I could imagine for it to do that would be to defined a standard typed data structure for binder transactions, so that it could read and verify the contents of the parcel. This puts too much knowledge in the kernel in my opinion, and for no real benefit. No matter how much you put there, user space will need to do some kind of validation of the incoming transaction to ensure it matches its expectations. Today this is done at the level of validating that primitive data read operations on Parcel (readBinder(), readString16(), readInt(), etc) are written to avoid attacks. Pushing more validation to the kernel will still require validation in user space that data types are correct, and now you have actually moved some opportunities for attacks (due to bugs in this code) from user space to the kernel.
One final thing about binder security is that it is important to realize that at the platform level there is another important security model implemented on top of the binder infrastructure. This is the permission/uid-based system, where services can check the uid of incoming calls to verify them against their allowed permissions.
This security model has another spoofing vulnerability that it must deal with. A typical scenario would be an application receiving the IBinder for the Activity Manager Service (since everyone can get that). The API of the Activity Manager Service is deeply based on checking the uid of incoming calls to determine what is allowed -- for example if a call to bindService() is made, it will check to see if that uid has permission to bind to the given service. A malicious app could try to play games here by handing the activity manager IBinder to another system service, for example as an IWindow to the window manager. If it knows the transactions that the second system service will make, it could set things up so that it makes a call that it thinks is say resizeWindow() but actually ends up becoming a call to bindService() when it comes put in the activity manager (if those two calls are mapped to the same transaction ID).
This vulnerability exists because the binder system is not typed in any way, "method" calls are simply transactions being sent with an integer transaction code and data buffer.
To protect against this, the user space typed interfaces generated by aidl always put at the start of their transaction buffer the name of the interface they are intending to call, and the receiving code of the transaction checks the interface name at the front of the buffer to ensure that it matches its own interace. This way the spoofer in the scenario above will be caught when the activity manager sees that it has an incoming call whose interface was for a window.
Anyway, for most practical use by Android developers, uid-based security is just as relevant as the core binder capability model. In some cases you will enforce security by restricting which processes get access to a binder. An example for this would be how there is an IBinder representing each activity, which only the system process and the process running the activity share.
In other cases and IBinder object will be shared with any interested processes, but enforce security at point of call based on uid. If you are using aidl to supply your standard implementation of such interfaces, your own implementation of such security can be done based on what meaning you want to apply to uids. For example, you could use the standard facility to associated permissions with uids and ask the package manager if the incoming uid has a permission.
The Binder has one identified security flaw which may make it susceptible to a MITM attack: http://crypto.hyperlink.cz/files/xbinder.pdf . To quote TFA:
the attacker can manage the target to further pass on or call its “protected” binder (that the attacker is not invited to call directly). We call this a cross-binder reference forgery (XBRF)
The author goes on to say that there are defenses in Android against this attack, but that
in some situations, a careful manipulation with the transaction data prepared by an attacking process may still lead to a successful XBRF exploit
One gets the impression that Binder seems to be relatively secure for carefully-written code, but there is some risk.

Categories

Resources