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

Commit 8c375feb authored by Jae Seo's avatar Jae Seo
Browse files

TIF: Use per-user ContentResolver in the TvInputManagerService

When switched to a different user (e.g. Restricted profile), the
TvInputManagerService continues to use the TV storage of the previous
user for logging, resulting in failure of the FOREIGN KEY constraint
since channel data for the current user don’t match to the logging data.
This change ensures that the system service uses the proper
ContentResolver when the user is switched.

Bug: 22047202
Change-Id: I870b5bd921e37a5f1219ea66c7a51314c77ddb01
parent 12402daf
Loading
Loading
Loading
Loading
+63 −42
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.content.OperationApplicationException;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.graphics.Rect;
@@ -112,8 +113,6 @@ public final class TvInputManagerService extends SystemService {
    private final Context mContext;
    private final TvInputHardwareManager mTvInputHardwareManager;

    private final ContentResolver mContentResolver;

    // A global lock.
    private final Object mLock = new Object();

@@ -129,9 +128,8 @@ public final class TvInputManagerService extends SystemService {
        super(context);

        mContext = context;
        mContentResolver = context.getContentResolver();
        mWatchLogHandler = new WatchLogHandler(mContentResolver, IoThread.get().getLooper());

        mWatchLogHandler = new WatchLogHandler(mContext.getContentResolver(),
                IoThread.get().getLooper());
        mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());

        synchronized (mLock) {
@@ -246,7 +244,8 @@ public final class TvInputManagerService extends SystemService {

                ContentProviderResult[] results = null;
                try {
                    results = mContentResolver.applyBatch(TvContract.AUTHORITY, operations);
                    ContentResolver cr = getContentResolverForUser(getChangingUserId());
                    results = cr.applyBatch(TvContract.AUTHORITY, operations);
                } catch (RemoteException | OperationApplicationException e) {
                    Slog.e(TAG, "error in applyBatch", e);
                }
@@ -400,17 +399,18 @@ public final class TvInputManagerService extends SystemService {
            if (mCurrentUserId == userId) {
                return;
            }
            // final int oldUserId = mCurrentUserId;
            // TODO: Release services and sessions in the old user state, if needed.
            mCurrentUserId = userId;
            clearSessionAndServiceStatesLocked(mUserStates.get(mCurrentUserId));

            mCurrentUserId = userId;
            UserState userState = mUserStates.get(userId);
            if (userState == null) {
                userState = new UserState(mContext, userId);
            }
                mUserStates.put(userId, userState);
            }
            buildTvInputListLocked(userId, null);
            buildTvContentRatingSystemListLocked(userId);
            mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_SWITCH_CONTENT_RESOLVER,
                    getContentResolverForUser(userId)).sendToTarget();
        }
    }

@@ -420,6 +420,21 @@ public final class TvInputManagerService extends SystemService {
            if (userState == null) {
                return;
            }
            clearSessionAndServiceStatesLocked(userState);

            // Clear everything else.
            userState.inputMap.clear();
            userState.packageSet.clear();
            userState.contentRatingSystemList.clear();
            userState.clientStateMap.clear();
            userState.callbackSet.clear();
            userState.mainSessionToken = null;

            mUserStates.remove(userId);
        }
    }

    private void clearSessionAndServiceStatesLocked(UserState userState) {
        // Release created sessions.
        for (SessionState state : userState.sessionStateMap.values()) {
            if (state.session != null) {
@@ -444,17 +459,18 @@ public final class TvInputManagerService extends SystemService {
            mContext.unbindService(serviceState.connection);
        }
        userState.serviceStateMap.clear();
    }

            // Clear everything else.
            userState.inputMap.clear();
            userState.packageSet.clear();
            userState.contentRatingSystemList.clear();
            userState.clientStateMap.clear();
            userState.callbackSet.clear();
            userState.mainSessionToken = null;

            mUserStates.remove(userId);
    private ContentResolver getContentResolverForUser(int userId) {
        UserHandle user = new UserHandle(userId);
        Context context;
        try {
            context = mContext.createPackageContextAsUser("android", 0, user);
        } catch (NameNotFoundException e) {
            Slog.e(TAG, "failed to create package contenxt as user " + user);
            context = mContext;
        }
        return context.getContentResolver();
    }

    private UserState getUserStateLocked(int userId) {
@@ -2384,12 +2400,13 @@ public final class TvInputManagerService extends SystemService {
        // Here the system supplies the database the smallest set of information only that is
        // sufficient to consolidate the log entries while minimizing database operations in the
        // system service.
        private static final int MSG_LOG_WATCH_START = 1;
        private static final int MSG_LOG_WATCH_END = 2;
        static final int MSG_LOG_WATCH_START = 1;
        static final int MSG_LOG_WATCH_END = 2;
        static final int MSG_SWITCH_CONTENT_RESOLVER = 3;

        private final ContentResolver mContentResolver;
        private ContentResolver mContentResolver;

        public WatchLogHandler(ContentResolver contentResolver, Looper looper) {
        WatchLogHandler(ContentResolver contentResolver, Looper looper) {
            super(looper);
            mContentResolver = contentResolver;
        }
@@ -2419,7 +2436,7 @@ public final class TvInputManagerService extends SystemService {

                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
                    args.recycle();
                    return;
                    break;
                }
                case MSG_LOG_WATCH_END: {
                    SomeArgs args = (SomeArgs) msg.obj;
@@ -2434,11 +2451,15 @@ public final class TvInputManagerService extends SystemService {

                    mContentResolver.insert(TvContract.WatchedPrograms.CONTENT_URI, values);
                    args.recycle();
                    return;
                    break;
                }
                case MSG_SWITCH_CONTENT_RESOLVER: {
                    mContentResolver = (ContentResolver) msg.obj;
                    break;
                }
                default: {
                    Slog.w(TAG, "Unhandled message code: " + msg.what);
                    return;
                    Slog.w(TAG, "unhandled message code: " + msg.what);
                    break;
                }
            }
        }