Add a new API to improve VR thread scheduling.
Adds a new API that enables device-specific scheduler optimizations for
latency-sensitive VR threads.
BUG: 29163534
Change-Id: I58d7be0eb266eca452c804cd07004784fb7daf2b
diff --git a/api/current.txt b/api/current.txt
index c631627..4687957 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3705,6 +3705,7 @@
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
+ method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
diff --git a/api/system-current.txt b/api/system-current.txt
index 3fa518a..a6212d27 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3841,6 +3841,7 @@
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
+ method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
diff --git a/api/test-current.txt b/api/test-current.txt
index 993f388..4b8ad4ea 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3705,6 +3705,7 @@
method public void moveTaskToFront(int, int);
method public void moveTaskToFront(int, int, android.os.Bundle);
method public deprecated void restartPackage(java.lang.String);
+ method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 31fe390..aaccbec 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3625,6 +3625,24 @@
}
/**
+ * Enable more aggressive scheduling for latency-sensitive low-runtime VR threads. Only one
+ * thread can be a VR thread in a process at a time, and that thread may be subject to
+ * restrictions on the amount of time it can run.
+ *
+ * To reset the VR thread for an application, a tid of 0 can be passed.
+ *
+ * @see android.os.Process#myTid()
+ * @param tid tid of the VR thread
+ */
+ public static void setVrThread(int tid) {
+ try {
+ ActivityManagerNative.getDefault().setVrThread(tid);
+ } catch (RemoteException e) {
+ // pass
+ }
+ }
+
+ /**
* The AppTask allows you to manage your own application's tasks.
* See {@link android.app.ActivityManager#getAppTasks()}
*/
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index cee5646..33df89d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2996,6 +2996,13 @@
reply.writeInt(result);
return true;
}
+ case SET_VR_THREAD_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final int tid = data.readInt();
+ setVrThread(tid);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -7031,5 +7038,19 @@
return res;
}
+ @Override
+ public void setVrThread(int tid)
+ throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(tid);
+ mRemote.transact(SET_VR_THREAD_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ return;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 3f7ff0b..c21acf7 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -658,6 +658,8 @@
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options)
throws RemoteException;
+ public void setVrThread(int tid) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -1044,4 +1046,5 @@
int START_CONFIRM_DEVICE_CREDENTIAL_INTENT = IBinder.FIRST_CALL_TRANSACTION + 374;
int SEND_IDLE_JOB_TRIGGER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 375;
int SEND_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 376;
+ int SET_VR_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 377;
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index f664e70..b9e46a5 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -322,6 +322,13 @@
*/
public static final int SCHED_IDLE = 5;
+ /**
+ * Reset scheduler choice on fork.
+ * @hide
+ */
+ public static final int SCHED_RESET_ON_FORK = 0x40000000;
+
+
// Keep in sync with SP_* constants of enum type SchedPolicy
// declared in system/core/include/cutils/sched_policy.h,
// except THREAD_GROUP_DEFAULT does not correspond to any SP_* value.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5893f90..fb52a49 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2310,6 +2310,20 @@
if (mInVrMode != vrMode) {
mInVrMode = vrMode;
mShowDialogs = shouldShowDialogs(mConfiguration, mInVrMode);
+ if (r.app != null) {
+ ProcessRecord proc = r.app;
+ if (proc.vrThreadTid > 0) {
+ if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
+ if (mInVrMode == true) {
+ Process.setThreadScheduler(proc.vrThreadTid,
+ Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+ } else {
+ Process.setThreadScheduler(proc.vrThreadTid,
+ Process.SCHED_OTHER, 0);
+ }
+ }
+ }
+ }
}
}
vrService.setVrMode(vrMode, requestedPackage, userId, callingPackage);
@@ -12507,6 +12521,34 @@
}
}
+ public void setVrThread(int tid) {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
+ throw new UnsupportedOperationException("VR mode not supported on this device!");
+ }
+
+ synchronized (this) {
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ final int pid = Binder.getCallingPid();
+ proc = mPidsSelfLocked.get(pid);
+ if (proc != null && mInVrMode && tid >= 0) {
+ // reset existing VR thread to CFS
+ if (proc.vrThreadTid != 0) {
+ Process.setThreadScheduler(proc.vrThreadTid, Process.SCHED_OTHER, 0);
+ }
+ // add check to guarantee that tid belongs to pid?
+ proc.vrThreadTid = tid;
+ // promote to FIFO now if the tid is non-zero
+ if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP && proc.vrThreadTid > 0) {
+ Process.setThreadScheduler(proc.vrThreadTid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+ }
+ } else {
+ //Slog.e("VR_FIFO", "Didn't set thread from setVrThread?");
+ }
+ }
+ }
+ }
+
@Override
public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) {
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
@@ -20106,6 +20148,7 @@
}
if (app.setSchedGroup != app.curSchedGroup) {
+ int oldSchedGroup = app.setSchedGroup;
app.setSchedGroup = app.curSchedGroup;
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Setting sched group of " + app.processName
@@ -20131,6 +20174,23 @@
long oldId = Binder.clearCallingIdentity();
try {
Process.setProcessGroup(app.pid, processGroup);
+ 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 (mInVrMode && app.vrThreadTid != 0) {
+ Process.setThreadScheduler(app.vrThreadTid,
+ Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+ }
+ }
+ } 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) {
+ Process.setThreadScheduler(app.vrThreadTid, Process.SCHED_OTHER, 0);
+ }
+ }
} catch (Exception e) {
Slog.w(TAG, "Failed setting process group of " + app.pid
+ " to " + app.curSchedGroup);
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 8911a3e..0f7c89d 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -97,6 +97,7 @@
int verifiedAdj; // The last adjustment that was verified as actually being set
int curSchedGroup; // Currently desired scheduling class
int setSchedGroup; // Last set to background scheduling class
+ int vrThreadTid; // Thread currently set for VR scheduling
int trimMemoryLevel; // Last selected memory trimming level
int curProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state
int repProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state
@@ -293,6 +294,7 @@
pw.print(" setSchedGroup="); pw.print(setSchedGroup);
pw.print(" systemNoUi="); pw.print(systemNoUi);
pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
+ pw.print(prefix); pw.print("vrThreadTid="); pw.print(vrThreadTid);
pw.print(prefix); pw.print("curProcState="); pw.print(curProcState);
pw.print(" repProcState="); pw.print(repProcState);
pw.print(" pssProcState="); pw.print(pssProcState);