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

Commit c855d65d authored by Henry Fang's avatar Henry Fang Committed by Automerger Merge Worker
Browse files

Merge "Handle multi-profile use cases in TvInputManagerService" into sc-dev am: ac816bd1

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13698062

Change-Id: I71cfafdaad0b9d0b42694da45327b738ba330a15
parents 9d7baa0b ac816bd1
Loading
Loading
Loading
Loading
+112 −37
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.graphics.Rect;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
@@ -76,6 +77,7 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Pair;
@@ -133,6 +135,7 @@ public final class TvInputManagerService extends SystemService {

    private final Context mContext;
    private final TvInputHardwareManager mTvInputHardwareManager;
    private final UserManager mUserManager;

    // A global lock.
    private final Object mLock = new Object();
@@ -140,6 +143,9 @@ public final class TvInputManagerService extends SystemService {
    // ID of the current user.
    @GuardedBy("mLock")
    private int mCurrentUserId = UserHandle.USER_SYSTEM;
    // IDs of the running managed profiles. Their parent user ID should be mCurrentUserId.
    @GuardedBy("mLock")
    private final Set<Integer> mRunningManagedProfile  = new HashSet<>();

    // A map from user id to UserState.
    @GuardedBy("mLock")
@@ -163,6 +169,7 @@ public final class TvInputManagerService extends SystemService {

        mActivityManager =
                (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);

        synchronized (mLock) {
            getOrCreateUserStateLocked(mCurrentUserId);
@@ -270,6 +277,8 @@ public final class TvInputManagerService extends SystemService {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
        intentFilter.addAction(Intent.ACTION_USER_STARTED);
        intentFilter.addAction(Intent.ACTION_USER_STOPPED);
        mContext.registerReceiverAsUser(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
@@ -278,6 +287,12 @@ public final class TvInputManagerService extends SystemService {
                    switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
                } else if (Intent.ACTION_USER_STARTED.equals(action)) {
                    int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                    startUser(userId);
                } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
                    int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                    stopUser(userId);
                }
            }
        }, UserHandle.ALL, intentFilter, null, null);
@@ -423,13 +438,73 @@ public final class TvInputManagerService extends SystemService {
        }
    }

    private void startUser(int userId) {
        synchronized (mLock) {
            if (userId == mCurrentUserId || mRunningManagedProfile.contains(userId)) {
                // user already started
                return;
            }
            UserInfo userInfo = mUserManager.getUserInfo(userId);
            UserInfo parentInfo = mUserManager.getProfileParent(userId);
            if (userInfo.isManagedProfile()
                    && parentInfo != null
                    && parentInfo.id == mCurrentUserId) {
                // only the children of the current user can be started in background
                startProfileLocked(userId);
            }
        }
    }

    private void stopUser(int userId) {
        if (userId == mCurrentUserId) {
            switchUser(ActivityManager.getCurrentUser());
            return;
        }

        releaseSessionOfUserLocked(userId);
        unbindServiceOfUserLocked(userId);
        mRunningManagedProfile.remove(userId);
    }

    private void startProfileLocked(int userId) {
        buildTvInputListLocked(userId, null);
        buildTvContentRatingSystemListLocked(userId);
        mRunningManagedProfile.add(userId);
    }

    private void switchUser(int userId) {
        synchronized (mLock) {
            if (mCurrentUserId == userId) {
                return;
            }
            if (mUserStates.contains(mCurrentUserId)) {
                UserState userState = getUserStateLocked(mCurrentUserId);
            UserInfo userInfo = mUserManager.getUserInfo(userId);
            if (userInfo.isManagedProfile()) {
                Slog.w(TAG, "cannot switch to a managed profile!");
                return;
            }

            for (int runningId : mRunningManagedProfile) {
                releaseSessionOfUserLocked(runningId);
                unbindServiceOfUserLocked(runningId);
            }
            mRunningManagedProfile.clear();
            releaseSessionOfUserLocked(mCurrentUserId);
            unbindServiceOfUserLocked(mCurrentUserId);

            mCurrentUserId = userId;
            buildTvInputListLocked(userId, null);
            buildTvContentRatingSystemListLocked(userId);
            mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_SWITCH_CONTENT_RESOLVER,
                    getContentResolverForUser(userId)).sendToTarget();
        }
    }

    @GuardedBy("mLock")
    private void releaseSessionOfUserLocked(int userId) {
        UserState userState = getUserStateLocked(userId);
        if (userState == null) {
            return;
        }
        List<SessionState> sessionStatesToRelease = new ArrayList<>();
        for (SessionState sessionState : userState.sessionStateMap.values()) {
            if (sessionState.session != null && !sessionState.isRecordingSession) {
@@ -444,7 +519,14 @@ public final class TvInputManagerService extends SystemService {
            }
            clearSessionAndNotifyClientLocked(sessionState);
        }
    }

    @GuardedBy("mLock")
    private void unbindServiceOfUserLocked(int userId) {
        UserState userState = getUserStateLocked(userId);
        if (userState == null) {
            return;
        }
        for (Iterator<ComponentName> it = userState.serviceStateMap.keySet().iterator();
                it.hasNext(); ) {
            ComponentName component = it.next();
@@ -463,15 +545,6 @@ public final class TvInputManagerService extends SystemService {
        }
    }

            mCurrentUserId = userId;
            getOrCreateUserStateLocked(userId);
            buildTvInputListLocked(userId, null);
            buildTvContentRatingSystemListLocked(userId);
            mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_SWITCH_CONTENT_RESOLVER,
                    getContentResolverForUser(userId)).sendToTarget();
        }
    }

    @GuardedBy("mLock")
    private void clearSessionAndNotifyClientLocked(SessionState state) {
        if (state.client != null) {
@@ -537,6 +610,7 @@ public final class TvInputManagerService extends SystemService {
            userState.mCallbacks.kill();
            userState.mainSessionToken = null;

            mRunningManagedProfile.remove(userId);
            mUserStates.remove(userId);

            if (userId == mCurrentUserId) {
@@ -635,7 +709,7 @@ public final class TvInputManagerService extends SystemService {
        }

        boolean shouldBind;
        if (userId == mCurrentUserId) {
        if (userId == mCurrentUserId || mRunningManagedProfile.contains(userId)) {
            shouldBind = !serviceState.sessionTokens.isEmpty() || serviceState.isHardware;
        } else {
            // For a non-current user,
@@ -1295,9 +1369,10 @@ public final class TvInputManagerService extends SystemService {
            String uniqueSessionId = UUID.randomUUID().toString();
            try {
                synchronized (mLock) {
                    if (userId != mCurrentUserId && !isRecordingSession) {
                        // A non-recording session of a background (non-current) user
                        // should not be created.
                    if (userId != mCurrentUserId && !mRunningManagedProfile.contains(userId)
                            && !isRecordingSession) {
                        // Only current user and its running managed profiles can create
                        // non-recording sessions.
                        // Let the client get onConnectionFailed callback for this case.
                        sendSessionTokenToClientLocked(client, inputId, null, null, seq);
                        return;