Use myUserId() only in registerContentObserver()
The reason for this is a bit subtle: we want to guarantee that when a content observer is registered using the public API, it is *always* bound to the host user's view of the data behind the observed Uri, never the calling user's. Now, the reason it was the calling user in the first place is that the Settings provider (and potentially any singleton provider) needs the observers underlying Cursors returned from query() to be tied to the caller's user, not the provider's host user. In order to accomplish that now that the public-facing behavior is always tied to the host user, the concrete class that implements the Cursor type handled by the Settings provider has been extended with a new hidden API for setting a notification observer tied to an arbitrary user; and then the provider explicitly downcasts the query result's Cursor to that class in order to register the notification observer. We can do this safely because this is platform code; if we change the way that these underlying cursors are constructed, we can just fix this point of call to follow along. If they get out of sync in the future, the Settings provider will scream bloody murder in the log and throw a crashing exception. Bug 7231549 Change-Id: I0aaceebb8b4108c56f8b9964ca7f9e698ddd91c8
This commit is contained in:
@@ -1219,7 +1219,7 @@ public abstract class ContentResolver {
|
||||
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
|
||||
ContentObserver observer)
|
||||
{
|
||||
registerContentObserver(uri, notifyForDescendents, observer, UserHandle.getCallingUserId());
|
||||
registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());
|
||||
}
|
||||
|
||||
/** @hide - designated user version */
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.database;
|
||||
import android.content.ContentResolver;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
@@ -350,6 +351,11 @@ public abstract class AbstractCursor implements CrossProcessCursor {
|
||||
* specific row URI, or a base URI for a whole class of content.
|
||||
*/
|
||||
public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
|
||||
setNotificationUri(cr, notifyUri, UserHandle.myUserId());
|
||||
}
|
||||
|
||||
/** @hide - set the notification uri but with an observer for a particular user's view */
|
||||
public void setNotificationUri(ContentResolver cr, Uri notifyUri, int userHandle) {
|
||||
synchronized (mSelfObserverLock) {
|
||||
mNotifyUri = notifyUri;
|
||||
mContentResolver = cr;
|
||||
@@ -357,7 +363,7 @@ public abstract class AbstractCursor implements CrossProcessCursor {
|
||||
mContentResolver.unregisterContentObserver(mSelfObserver);
|
||||
}
|
||||
mSelfObserver = new SelfContentObserver(this);
|
||||
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
|
||||
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver, userHandle);
|
||||
mSelfObserverRegistered = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.database.AbstractCursor;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
@@ -685,7 +686,16 @@ public class SettingsProvider extends ContentProvider {
|
||||
qb.setTables(args.table);
|
||||
|
||||
Cursor ret = qb.query(db, select, args.where, args.args, null, null, sort);
|
||||
ret.setNotificationUri(getContext().getContentResolver(), url);
|
||||
// the default Cursor interface does not support per-user observation
|
||||
try {
|
||||
AbstractCursor c = (AbstractCursor) ret;
|
||||
c.setNotificationUri(getContext().getContentResolver(), url, forUser);
|
||||
} catch (ClassCastException e) {
|
||||
// details of the concrete Cursor implementation have changed and this code has
|
||||
// not been updated to match -- complain and fail hard.
|
||||
Log.wtf(TAG, "Incompatible cursor derivation!");
|
||||
throw e;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user