Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7564454 authored by Christopher Tate's avatar Christopher Tate
Browse files

Multiuser awareness in content observer infrastructure

Content observers are registered under the calling user's identity,
not under the provider host's identity (unless the caller is using
the new permissioned entry points that allow observers to be
registered for a different user's view of the data).  The most important
implication of this is that when the settings provider is directly
queried, the Cursor returned to the app is wired for change notifications
based on that calling app's user.

Note that it is not possible to use query() / insert() to read/write
data for different users.  All such manipulations should use the
standard get* / put* methods in Settings.*.

Bug 7122169

Change-Id: If5d9ec44927e5e56e4e7635438f4ef48a5430986
parent 314488b7
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1219,7 +1219,7 @@ public abstract class ContentResolver {
    public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
            ContentObserver observer)
    {
        registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());
        registerContentObserver(uri, notifyForDescendents, observer, UserHandle.getCallingUserId());
    }

    /** @hide - designated user version */
@@ -1283,7 +1283,7 @@ public abstract class ContentResolver {
     * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
     */
    public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
        notifyChange(uri, observer, syncToNetwork, UserHandle.myUserId());
        notifyChange(uri, observer, syncToNetwork, UserHandle.getCallingUserId());
    }

    /**
+0 −4
Original line number Diff line number Diff line
@@ -154,15 +154,11 @@ public final class ContentService extends IContentService.Stub {
            throw new IllegalArgumentException("You must pass a valid uri and observer");
        }

        // STOPSHIP: disable the multi-user permission checks until a solid fix for the
        // content provider / observer case is in place.
        /*
        final int callingUser = UserHandle.getCallingUserId();
        if (callingUser != userHandle) {
            mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                    "no permission to observe other users' provider view");
        }
        */

        if (userHandle < 0) {
            if (userHandle == UserHandle.USER_CURRENT) {
+53 −51
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.backup.BackupManager;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
@@ -33,20 +32,17 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.sqlite.SQLiteStatement;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.FileObserver;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -656,10 +652,13 @@ public class SettingsProvider extends ContentProvider {
            }
        }

        // Okay, permission checks have cleared.  Reset to our own identity so we can
        // manipulate all users' data with impunity.
        long oldId = Binder.clearCallingIdentity();
        try {
            // Note: we assume that get/put operations for moved-to-global names have already
            // been directed to the new location on the caller side (otherwise we'd fix them
            // up here).

            DatabaseHelper dbHelper;
            SettingsCache cache;

@@ -704,6 +703,9 @@ public class SettingsProvider extends ContentProvider {
            } else {
                Slog.w(TAG, "call() with invalid method: " + method);
            }
        } finally {
            Binder.restoreCallingIdentity(oldId);
        }

        return null;
    }
@@ -758,7 +760,7 @@ public class SettingsProvider extends ContentProvider {
        return queryForUser(url, select, where, whereArgs, sort, UserHandle.getCallingUserId());
    }

    public Cursor queryForUser(Uri url, String[] select, String where, String[] whereArgs,
    private Cursor queryForUser(Uri url, String[] select, String where, String[] whereArgs,
            String sort, int forUser) {
        if (LOCAL_LOGV) Slog.v(TAG, "query(" + url + ") for user " + forUser);
        SqlArguments args = new SqlArguments(url, where, whereArgs);