diff options
| -rw-r--r-- | core/java/android/app/ActivityManagerNative.java | 22 | ||||
| -rw-r--r-- | core/java/android/app/IActivityManager.java | 4 | ||||
| -rw-r--r-- | core/java/android/os/Process.java | 20 | ||||
| -rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 12 | ||||
| -rw-r--r-- | core/jni/android_view_ThreadedRenderer.cpp | 7 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 4 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 1 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 123 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ProcessList.java | 3 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ProcessRecord.java | 2 |
10 files changed, 166 insertions, 32 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 14f9db732514..277348a318b9 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -3003,6 +3003,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + case SET_RENDER_THREAD_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final int tid = data.readInt(); + setRenderThread(tid); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -7040,7 +7047,7 @@ class ActivityManagerProxy implements IActivityManager @Override public void setVrThread(int tid) - throws RemoteException { + throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); @@ -7052,5 +7059,18 @@ class ActivityManagerProxy implements IActivityManager return; } + public void setRenderThread(int tid) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(tid); + mRemote.transact(SET_RENDER_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 d38fb94161f5..4a4202aa4ce8 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -659,6 +659,7 @@ public interface IActivityManager extends IInterface { throws RemoteException; public void setVrThread(int tid) throws RemoteException; + public void setRenderThread(int tid) throws RemoteException; /* * Private non-Binder interfaces @@ -1046,5 +1047,8 @@ public interface IActivityManager extends IInterface { 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; + + // Start of N MR1 transactions int SET_VR_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 377; + int SET_RENDER_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 378; } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index b9e46a5c60f1..c26d974b2cba 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -19,6 +19,7 @@ package android.os; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.system.Os; +import android.system.OsConstants; import android.util.Log; import com.android.internal.os.Zygote; import dalvik.system.VMRuntime; @@ -328,7 +329,6 @@ public class Process { */ 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. @@ -1250,4 +1250,22 @@ public class Process { * @hide */ public static final native void removeAllProcessGroups(); + + /** + * Check to see if a thread belongs to a given process. This may require + * more permissions than apps generally have. + * @return true if this thread belongs to a process + * @hide + */ + public static final boolean isThreadInProcess(int tid, int pid) { + try { + if (Os.access("/proc/" + tid + "/task/" + pid, OsConstants.F_OK)) { + return true; + } else { + return false; + } + } catch (Exception e) { + return false; + } + } } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index fcca7395fe8c..e129a067ec14 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -16,6 +16,7 @@ package android.view; +import android.app.ActivityManagerNative; import android.annotation.IntDef; import android.annotation.NonNull; import android.content.Context; @@ -917,10 +918,20 @@ public final class ThreadedRenderer { synchronized void init(Context context, long renderProxy) { if (mInitialized) return; mInitialized = true; + initSched(context, renderProxy); initGraphicsStats(context, renderProxy); initAssetAtlas(context, renderProxy); } + private static void initSched(Context context, long renderProxy) { + try { + int tid = nGetRenderThreadTid(renderProxy); + ActivityManagerNative.getDefault().setRenderThread(tid); + } catch (Throwable t) { + Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t); + } + } + private static void initGraphicsStats(Context context, long renderProxy) { try { IBinder binder = ServiceManager.getService("graphicsstats"); @@ -979,6 +990,7 @@ public final class ThreadedRenderer { private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map); private static native void nSetProcessStatsBuffer(long nativeProxy, int fd); + private static native int nGetRenderThreadTid(long nativeProxy); private static native long nCreateRootRenderNode(); private static native long nCreateProxy(boolean translucent, long rootRenderNode); diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 9e4da989a024..bff057b237b6 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -542,6 +542,12 @@ static void android_view_ThreadedRenderer_setProcessStatsBuffer(JNIEnv* env, job proxy->setProcessStatsBuffer(fd); } +static jint android_view_ThreadedRenderer_getRenderThreadTid(JNIEnv* env, jobject clazz, + jlong proxyPtr) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); + return proxy->getRenderThreadTid(); +} + static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) { RootRenderNode* node = new RootRenderNode(env); node->incStrong(0); @@ -857,6 +863,7 @@ const char* const kClassPathName = "android/view/ThreadedRenderer"; static const JNINativeMethod gMethods[] = { { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V", (void*) android_view_ThreadedRenderer_setAtlas }, { "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer }, + { "nGetRenderThreadTid", "(J)I", (void*) android_view_ThreadedRenderer_getRenderThreadTid }, { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode }, { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy }, { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy }, diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 54af2829cf40..06a24b248bf6 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -514,6 +514,10 @@ void RenderProxy::setProcessStatsBuffer(int fd) { post(task); } +int RenderProxy::getRenderThreadTid() { + return mRenderThread.getTid(); +} + CREATE_BRIDGE3(addRenderNode, CanvasContext* context, RenderNode* node, bool placeFront) { args->context->addRenderNode(args->node, args->placeFront); return nullptr; diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 898b31421aad..e31062c83734 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -115,6 +115,7 @@ public: ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size); ANDROID_API void setProcessStatsBuffer(int fd); + ANDROID_API int getRenderThreadTid(); ANDROID_API void serializeDisplayListTree(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 9fcbf53e0080..5bfb90f9bb57 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -569,6 +569,9 @@ public final class ActivityManagerService extends ActivityManagerNative private boolean mShowDialogs = true; private boolean mInVrMode = false; + // Whether we should use SCHED_FIFO for UI and RenderThreads. + private boolean mUseFifoUiScheduling = false; + BroadcastQueue mFgBroadcastQueue; BroadcastQueue mBgBroadcastQueue; // Convenient for easy iteration over the queues. Foreground is first @@ -2657,6 +2660,10 @@ public final class ActivityManagerService extends ActivityManagerNative GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED); + if (SystemProperties.getInt("sys.use_fifo_ui", 0) != 0) { + mUseFifoUiScheduling = true; + } + mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations")); mConfiguration.setToDefaults(); @@ -12532,6 +12539,10 @@ public final class ActivityManagerService extends ActivityManagerNative final int pid = Binder.getCallingPid(); proc = mPidsSelfLocked.get(pid); if (proc != null && mInVrMode && tid >= 0) { + // ensure the tid belongs to the process + if (!Process.isThreadInProcess(pid, tid)) { + throw new IllegalArgumentException("VR thread does not belong to process"); + } // reset existing VR thread to CFS if (proc.vrThreadTid != 0) { Process.setThreadScheduler(proc.vrThreadTid, Process.SCHED_OTHER, 0); @@ -12550,6 +12561,40 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override + public void setRenderThread(int tid) { + synchronized (this) { + ProcessRecord proc; + synchronized (mPidsSelfLocked) { + int pid = Binder.getCallingPid(); + proc = mPidsSelfLocked.get(pid); + if (mUseFifoUiScheduling && proc != null && proc.renderThreadTid == 0 && tid > 0) { + // ensure the tid belongs to the process + if (!Process.isThreadInProcess(pid, tid)) { + throw new IllegalArgumentException( + "Render thread does not belong to process"); + } + proc.renderThreadTid = tid; + if (DEBUG_OOM_ADJ) { + Slog.d("UI_FIFO", "Set RenderThread tid " + tid + " for pid " + pid); + } + // promote to FIFO now + if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) { + if (DEBUG_OOM_ADJ) Slog.d("UI_FIFO", "Promoting " + tid + "out of band"); + Process.setThreadScheduler(proc.renderThreadTid, + Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1); + } + } else { + if (DEBUG_OOM_ADJ) { + Slog.d("UI_FIFO", "Didn't set thread from setRenderThread? " + + "PID: " + pid + ", TID: " + tid + " FIFO: " + + mUseFifoUiScheduling); + } + } + } + } + } + + @Override public int setVrMode(IBinder token, boolean enabled, ComponentName packageName) { if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) { throw new UnsupportedOperationException("VR mode not supported on this device!"); @@ -19547,7 +19592,7 @@ public final class ActivityManagerService extends ActivityManagerNative adj = ProcessList.FOREGROUND_APP_ADJ; if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) { if ((cr.flags&Context.BIND_IMPORTANT) != 0) { - schedGroup = ProcessList.SCHED_GROUP_TOP_APP; + schedGroup = ProcessList.SCHED_GROUP_TOP_APP_BOUND; } else { schedGroup = ProcessList.SCHED_GROUP_DEFAULT; } @@ -20164,47 +20209,65 @@ public final class ActivityManagerService extends ActivityManagerNative processGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; break; case ProcessList.SCHED_GROUP_TOP_APP: + case ProcessList.SCHED_GROUP_TOP_APP_BOUND: processGroup = Process.THREAD_GROUP_TOP_APP; break; default: processGroup = Process.THREAD_GROUP_DEFAULT; break; } - if (true) { - 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, + 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); + } + if (mUseFifoUiScheduling) { + // Switch UI pipeline for app to SCHED_FIFO + app.savedPriority = Process.getThreadPriority(app.pid); + Process.setThreadScheduler(app.pid, + Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1); + if (app.renderThreadTid != 0) { + Process.setThreadScheduler(app.renderThreadTid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1); + if (DEBUG_OOM_ADJ) { + Slog.d("UI_FIFO", "Set RenderThread (TID " + + app.renderThreadTid + ") to FIFO"); + } + } else { + if (DEBUG_OOM_ADJ) { + Slog.d("UI_FIFO", "Not setting RenderThread TID"); + } } } - } 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); - e.printStackTrace(); - } finally { - Binder.restoreCallingIdentity(oldId); - } - } else { - if (app.thread != null) { - try { - app.thread.setSchedulingGroup(processGroup); - } catch (RemoteException e) { + } 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); + } + if (mUseFifoUiScheduling) { + // Reset UI pipeline to SCHED_OTHER + Process.setThreadScheduler(app.pid, Process.SCHED_OTHER, 0); + Process.setThreadScheduler(app.renderThreadTid, + Process.SCHED_OTHER, 0); + Process.setThreadPriority(app.pid, app.savedPriority); + Process.setThreadPriority(app.renderThreadTid, -4); } } + } catch (Exception e) { + Slog.w(TAG, "Failed setting process group of " + app.pid + + " to " + app.curSchedGroup); + e.printStackTrace(); + } finally { + Binder.restoreCallingIdentity(oldId); } } } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index f073e5cd4fda..475b155d8d21 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -130,6 +130,9 @@ final class ProcessList { static final int SCHED_GROUP_DEFAULT = 1; // Activity manager's version of Process.THREAD_GROUP_TOP_APP static final int SCHED_GROUP_TOP_APP = 2; + // Activity manager's version of Process.THREAD_GROUP_TOP_APP + // Disambiguate between actual top app and processes bound to the top app + static final int SCHED_GROUP_TOP_APP_BOUND = 3; // The minimum number of cached apps we want to be able to keep around, // without empty apps being able to push them out of memory. diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 0f7c89dc9506..dad383dff22f 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -103,6 +103,8 @@ final class ProcessRecord { int repProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state int setProcState = PROCESS_STATE_NONEXISTENT; // Last set process state in process tracker int pssProcState = PROCESS_STATE_NONEXISTENT; // Currently requesting pss for + int savedPriority; // Previous priority value if we're switching to non-SCHED_OTHER + int renderThreadTid; // TID for RenderThread boolean serviceb; // Process currently is on the service B list boolean serviceHighRam; // We are forcing to service B list due to its RAM use boolean setIsForeground; // Running foreground UI when last set? |