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

Commit e002ce70 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Refactor VR state management in ActivityManagerService." into oc-dev

parents ff5eb06e 279d34af
Loading
Loading
Loading
Loading
+65 −207
Original line number Diff line number Diff line
@@ -333,7 +333,6 @@ import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.VoiceInteractionManagerInternal;
import android.service.voice.VoiceInteractionSession;
import android.service.vr.IPersistentVrStateCallbacks;
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -664,70 +663,8 @@ public class ActivityManagerService extends IActivityManager.Stub
    // default action automatically.  Important for devices without direct input
    // devices.
    private boolean mShowDialogs = true;
    // VR state flags.
    static final int NON_VR_MODE = 0;
    static final int VR_MODE = 1;
    static final int PERSISTENT_VR_MODE = 2;
    private int mVrState = NON_VR_MODE;
    private int mTopAppVrThreadTid = 0;
    private int mPersistentVrThreadTid = 0;
    final IPersistentVrStateCallbacks mPersistentVrModeListener =
            new IPersistentVrStateCallbacks.Stub() {
        @Override
        public void onPersistentVrStateChanged(boolean enabled) {
            synchronized(ActivityManagerService.this) {
                // There are 4 possible cases here:
                //
                // Cases for enabled == true
                // Invariant: mVrState != PERSISTENT_VR_MODE;
                //    This is guaranteed as only this function sets mVrState to PERSISTENT_VR_MODE
                // Invariant: mPersistentVrThreadTid == 0
                //   This is guaranteed by VrManagerService, which only emits callbacks when the
                //   mode changes, and in setPersistentVrThread, which only sets
                //   mPersistentVrThreadTid when mVrState = PERSISTENT_VR_MODE
                // Case 1: mTopAppVrThreadTid > 0 (someone called setVrThread successfully and is
                // the top-app)
                //     We reset the app which currently has SCHED_FIFO (mPersistentVrThreadTid) to
                //     SCHED_OTHER
                // Case 2: mTopAppVrThreadTid == 0
                //     Do nothing
                //
                // Cases for enabled == false
                // Invariant: mVrState == PERSISTENT_VR_MODE;
                //     This is guaranteed by VrManagerService, which only emits callbacks when the
                //     mode changes, and the only other assignment of mVrState outside of this
                //     function checks if mVrState != PERSISTENT_VR_MODE
                // Invariant: mTopAppVrThreadTid == 0
                //     This is guaranteed in that mTopAppVrThreadTid is only set to a tid when
                //     mVrState is VR_MODE, and is explicitly set to 0 when setPersistentVrThread is
                //     called
                //   mPersistentVrThreadTid > 0 (someone called setPersistentVrThread successfully)
                //     3. Reset mPersistentVrThreadTidto SCHED_OTHER
                //   mPersistentVrThreadTid == 0
                //     4. Do nothing
                if (enabled) {
                    mVrState = PERSISTENT_VR_MODE;
                } else {
                    // Leaving persistent mode implies leaving VR mode.
                    mVrState = NON_VR_MODE;
                }
                if (mVrState == PERSISTENT_VR_MODE) {
                    if (mTopAppVrThreadTid > 0) {
                        // Ensure that when entering persistent VR mode the last top-app loses
                        // SCHED_FIFO.
                        setThreadScheduler(mTopAppVrThreadTid, SCHED_OTHER, 0);
                        mTopAppVrThreadTid = 0;
                    }
                } else if (mPersistentVrThreadTid > 0) {
                    // Ensure that when leaving persistent VR mode we reschedule the high priority
                    // persistent thread.
                    setThreadScheduler(mPersistentVrThreadTid, SCHED_OTHER, 0);
                    mPersistentVrThreadTid = 0;
                }
            }
        }
    };
    private final VrController mVrController;
    // VR Compatibility Display Id.
    int mVrCompatibilityDisplayId = INVALID_DISPLAY;
@@ -2447,53 +2384,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                idleUids();
            } break;
            case VR_MODE_CHANGE_MSG: {
                VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
                if (vrService == null) {
                    break;
                }
                final ActivityRecord r = (ActivityRecord) msg.obj;
                boolean vrMode;
                boolean inVrMode;
                ComponentName requestedPackage;
                ComponentName callingPackage;
                int userId;
                synchronized (ActivityManagerService.this) {
                    vrMode = r.requestedVrComponent != null;
                    inVrMode = mVrState != NON_VR_MODE;
                    requestedPackage = r.requestedVrComponent;
                    userId = r.userId;
                    callingPackage = r.info.getComponentName();
                    if (vrMode != inVrMode) {
                        // Don't change state if we're in persistent VR mode, but do update thread
                        // priorities if necessary.
                        if (mVrState != PERSISTENT_VR_MODE) {
                            mVrState = vrMode ? VR_MODE : NON_VR_MODE;
                        }
                        mShowDialogs = shouldShowDialogs(getGlobalConfiguration(), vrMode);
                        if (r.app != null) {
                            ProcessRecord proc = r.app;
                            if (proc.vrThreadTid > 0) {
                                if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                                    try {
                                        if (mVrState == VR_MODE) {
                                            setThreadScheduler(proc.vrThreadTid,
                                                SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                            mTopAppVrThreadTid = proc.vrThreadTid;
                                        } else {
                                            setThreadScheduler(proc.vrThreadTid,
                                                SCHED_OTHER, 0);
                                            mTopAppVrThreadTid = 0;
                                        }
                                    } catch (IllegalArgumentException e) {
                                        Slog.w(TAG, "Failed to set scheduling policy, thread does"
                                                + " not exist:\n" + e);
                                    }
                                }
                            }
                        }
                    }
                }
                vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage);
                mVrController.onVrModeChanged((ActivityRecord) msg.obj);
            } break;
            case NOTIFY_VR_SLEEPING_MSG: {
                notifyVrManagerOfSleepState(msg.arg1 != 0);
@@ -2770,6 +2661,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        mTaskChangeNotificationController = null;
        mUiHandler = injector.getUiHandler(null);
        mUserController = null;
        mVrController = null;
    }
    // Note: This method is invoked on the main thread but may need to attach various
@@ -2856,6 +2748,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        mUserController = new UserController(this);
        mVrController = new VrController(this);
        GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
            ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -13263,23 +13157,12 @@ public class ActivityManagerService extends IActivityManager.Stub
    @Override
    public void setVrThread(int tid) {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
            throw new UnsupportedOperationException("VR mode not supported on this device!");
        }
        enforceSystemHasVrFeature();
        synchronized (this) {
            if (tid > 0 && mVrState == PERSISTENT_VR_MODE) {
                Slog.e(TAG, "VR thread cannot be set in persistent VR mode!");
                return;
            }
            ProcessRecord proc;
            synchronized (mPidsSelfLocked) {
                final int pid = Binder.getCallingPid();
                proc = mPidsSelfLocked.get(pid);
                if (proc != null && mVrState == VR_MODE && tid >= 0) {
                    proc.vrThreadTid = updateVrThreadLocked(proc, proc.vrThreadTid, pid, tid);
                    mTopAppVrThreadTid = proc.vrThreadTid;
                }
                final ProcessRecord proc = mPidsSelfLocked.get(pid);
                mVrController.setVrThreadLocked(tid, pid, proc);
            }
        }
    }
@@ -13287,72 +13170,71 @@ public class ActivityManagerService extends IActivityManager.Stub
    @Override
    public void setPersistentVrThread(int tid) {
        if (checkCallingPermission(permission.RESTRICTED_VR_ACCESS) != PERMISSION_GRANTED) {
            String msg = "Permission Denial: setPersistentVrThread() from pid="
            final String msg = "Permission Denial: setPersistentVrThread() from pid="
                    + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid()
                    + " requires " + permission.RESTRICTED_VR_ACCESS;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
            throw new UnsupportedOperationException("VR mode not supported on this device!");
        }
        enforceSystemHasVrFeature();
        synchronized (this) {
            // Disable any existing VR thread.
            if (mTopAppVrThreadTid > 0) {
                setThreadScheduler(mTopAppVrThreadTid, SCHED_OTHER, 0);
                mTopAppVrThreadTid = 0;
            }
            if (tid > 0 && mVrState != PERSISTENT_VR_MODE) {
                Slog.e(TAG, "Persistent VR thread may only be set in persistent VR mode!");
                return;
            }
            ProcessRecord proc;
            synchronized (mPidsSelfLocked) {
                final int pid = Binder.getCallingPid();
                mPersistentVrThreadTid =
                        updateVrThreadLocked(null, mPersistentVrThreadTid, pid, tid);
                final ProcessRecord proc = mPidsSelfLocked.get(pid);
                mVrController.setPersistentVrThreadLocked(tid, pid, proc);
            }
        }
    }
    /**
     * Used by setVrThread and setPersistentVrThread to update a thread's priority. When proc is
     * non-null it must be in SCHED_GROUP_TOP_APP.  When it is null, the tid is unconditionally
     * rescheduled.
     * Schedule the given thread a normal scheduling priority.
     *
     * @param newTid the tid of the thread to adjust the scheduling of.
     * @param suppressLogs {@code true} if any error logging should be disabled.
     *
     * @return {@code true} if this succeeded.
     */
    private int updateVrThreadLocked(ProcessRecord proc, int lastTid, int pid, int tid) {
        // ensure the tid belongs to the process
        if (!isThreadInProcess(pid, tid)) {
            throw new IllegalArgumentException("VR thread does not belong to process");
        }
        // reset existing VR thread to CFS if this thread still exists and belongs to
        // the calling process
        if (lastTid != 0 && isThreadInProcess(pid, lastTid)) {
    static boolean scheduleAsRegularPriority(int tid, boolean suppressLogs) {
        try {
                setThreadScheduler(lastTid, SCHED_OTHER, 0);
            Process.setThreadScheduler(tid, Process.SCHED_OTHER, 0);
            return true;
        } catch (IllegalArgumentException e) {
                // Ignore this.  Only occurs in race condition where previous VR thread
                // was destroyed during this method call.
            if (!suppressLogs) {
                Slog.w(TAG, "Failed to set scheduling policy, thread does not exist:\n" + e);
            }
        }
        return false;
    }
        // promote to FIFO now if the tid is non-zero
    /**
     * Schedule the given thread an FIFO scheduling priority.
     *
     * @param newTid the tid of the thread to adjust the scheduling of.
     * @param suppressLogs {@code true} if any error logging should be disabled.
     *
     * @return {@code true} if this succeeded.
     */
    static boolean scheduleAsFifoPriority(int tid, boolean suppressLogs) {
        try {
            if ((proc == null || proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP)
                    && tid > 0) {
                setThreadScheduler(tid,
                    SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
            }
            return tid;
            Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
            return true;
        } catch (IllegalArgumentException e) {
            Slog.e(TAG, "Failed to set scheduling policy, thread does"
                   + " not exist:\n" + e);
            if (!suppressLogs) {
                Slog.w(TAG, "Failed to set scheduling policy, thread does not exist:\n" + e);
            }
        }
        return false;
    }
    /**
     * Check that we have the features required for VR-related API calls, and throw an exception if
     * not.
     */
    private void enforceSystemHasVrFeature() {
        if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
            throw new UnsupportedOperationException("VR mode not supported on this device!");
        }
        return lastTid;
    }
    @Override
@@ -13944,10 +13826,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            mLocalDeviceIdleController
                    = LocalServices.getService(DeviceIdleController.LocalService.class);
            mAssistUtils = new AssistUtils(mContext);
            VrManagerInternal vrManagerInternal = LocalServices.getService(VrManagerInternal.class);
            if (vrManagerInternal != null) {
                vrManagerInternal.addPersistentVrModeStateListener(mPersistentVrModeListener);
            }
            mVrController.onSystemReady();
            // Make sure we have the current profile info, since it is needed for security checks.
            mUserController.onSystemReady();
            mRecentTasks.onSystemReadyLocked();
@@ -15629,6 +15508,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                pw.println("  mVoiceWakeLock" + mVoiceWakeLock);
            }
        }
        pw.println("  mVrController=" + mVrController);
        if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
                || mOrigWaitForDebugger) {
            if (dumpPackage == null || dumpPackage.equals(mDebugApp)
@@ -20055,7 +19935,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                mUserController.getCurrentUserIdLocked());
        // TODO: If our config changes, should we auto dismiss any currently showing dialogs?
        mShowDialogs = shouldShowDialogs(mTempConfig, mVrState != NON_VR_MODE);
        mShowDialogs = shouldShowDialogs(mTempConfig);
        AttributeCache ac = AttributeCache.instance();
        if (ac != null) {
@@ -20285,15 +20165,16 @@ public class ActivityManagerService extends IActivityManager.Stub
     * A thought: SystemUI might also want to get told about this, the Power
     * dialog / global actions also might want different behaviors.
     */
    private static boolean shouldShowDialogs(Configuration config, boolean inVrMode) {
    private static boolean shouldShowDialogs(Configuration config) {
        final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS
                                   && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
                                   && config.navigation == Configuration.NAVIGATION_NONAV);
        int modeType = config.uiMode & Configuration.UI_MODE_TYPE_MASK;
        final boolean uiModeSupportsDialogs = (modeType != Configuration.UI_MODE_TYPE_CAR
                && !(modeType == Configuration.UI_MODE_TYPE_WATCH && "user".equals(Build.TYPE))
                && modeType != Configuration.UI_MODE_TYPE_TELEVISION);
        return inputMethodExists && uiModeSupportsDialogs && !inVrMode;
                && modeType != Configuration.UI_MODE_TYPE_TELEVISION
                && modeType != Configuration.UI_MODE_TYPE_VR_HEADSET);
        return inputMethodExists && uiModeSupportsDialogs;
    }
    @Override
@@ -21596,32 +21477,14 @@ public class ActivityManagerService extends IActivityManager.Stub
                    if (app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                        // do nothing if we already switched to RT
                        if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
                            // Switch VR thread for app to SCHED_FIFO
                            if (mVrState == VR_MODE && app.vrThreadTid != 0) {
                                try {
                                    setThreadScheduler(app.vrThreadTid,
                                        SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                    mTopAppVrThreadTid = app.vrThreadTid;
                                } catch (IllegalArgumentException e) {
                                    // thread died, ignore
                                }
                            }
                            mVrController.onTopProcChangedLocked(app);
                            if (mUseFifoUiScheduling) {
                                // Switch UI pipeline for app to SCHED_FIFO
                                app.savedPriority = getThreadPriority(app.pid);
                                try {
                                    setThreadScheduler(app.pid,
                                        SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                } catch (IllegalArgumentException e) {
                                    // thread died, ignore
                                }
                                app.savedPriority = Process.getThreadPriority(app.pid);
                                scheduleAsFifoPriority(app.pid, /* suppressLogs */true);
                                if (app.renderThreadTid != 0) {
                                    try {
                                        setThreadScheduler(app.renderThreadTid,
                                            SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                    } catch (IllegalArgumentException e) {
                                        // thread died, ignore
                                    }
                                    scheduleAsFifoPriority(app.renderThreadTid,
                                        /* suppressLogs */true);
                                    if (DEBUG_OOM_ADJ) {
                                        Slog.d("UI_FIFO", "Set RenderThread (TID " +
                                            app.renderThreadTid + ") to FIFO");
@@ -21645,12 +21508,7 @@ public class ActivityManagerService extends IActivityManager.Stub
                        }
                    } else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
                               app.curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
                        // Reset VR thread to SCHED_OTHER
                        // Safe to do even if we're not in VR mode
                        if (app.vrThreadTid != 0) {
                            setThreadScheduler(app.vrThreadTid, SCHED_OTHER, 0);
                            mTopAppVrThreadTid = 0;
                        }
                        mVrController.onTopProcChangedLocked(app);
                        if (mUseFifoUiScheduling) {
                            // Reset UI pipeline to SCHED_OTHER
                            setThreadScheduler(app.pid, SCHED_OTHER, 0);
+418 −0

File added.

Preview size limit exceeded, changes collapsed.