Fix races when content providers are acquired and released.

This change fixes race conditions that occur very regularly when
content providers are accessed from multiple threads at the same
time.

When a content provider is not already in the application's cache,
the application needs to ask the ActivityManager to obtain it.
Meanwhile, another thread can come along and do the same thing.
This can cause problems because the application attempts to
install two copies of the provider and the reference counts
and other bookkeeping can get muddled.

Similarly, there are races between releasing the last reference
to a content provider and acquiring the content provider.  It's
possible for one thread to snatch the content provider from the
jaws of death.  We need to handle this explicitly to ensure that
the content provider does not accidentally get released right
after it was acquired by the other thread.

This change ensures that the reference count bookkeeping and
provider map are maintained in parallel while holding the same lock.
Previously because the lock was dropped and reacquired in the
middle of acquisition and removal, it was possible for a
content provider with a zero reference count to be returned
to the application.  Likewise, it was possible for a content
provider with a non-zero reference count to be disposed!

This change also performs compensatory actions when races are
detected to ensure that the necessary invariants are maintained
throughout.  In particular, it ensures that the application
drops a duplicate reference to a content provider when no
longer needed.

Another way to solve this problem would be to explicitly prevent
the races from happening in the first place by maintaining a
table of content providers that are in the process of being
acquired.  The first thread to attempt to acquire the provider
would store a record.  The next thread would find the record
and block until the first thread was finished.  I chose not
to implement the code in that manner because we would still
have needed to perform compensatory actions in the case where
the same provider binder has multiple logical names.  Also,
it could cause deadlocks if the attempt to acquire
a content provider were re-entrant for some bizarre reason.

Bug: 5547357
Change-Id: I2ad39a8acc30aaf7ae5354decd0a0a41e9b9c3da
1 file changed