Boost thread priority when holding the WM lock

Test: Take systrace of open app, make sure thead is boosted while
doing stuff in WM
Test: Run WmSlam with and without boosting. Observe an
improvement.
Bug: 36631902
Change-Id: Iadb036f8d12bbf59091466500e82207cf6fa85d5
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 099f557..8003d21 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -39,8 +39,8 @@
 
 LOCAL_JACK_FLAGS := \
  -D jack.transformations.boost-locked-region-priority=true \
- -D jack.transformations.boost-locked-region-priority.classname=com.android.server.am.ActivityManagerService \
- -D jack.transformations.boost-locked-region-priority.request=com.android.server.am.ActivityManagerService\#boostPriorityForLockedSection \
- -D jack.transformations.boost-locked-region-priority.reset=com.android.server.am.ActivityManagerService\#resetPriorityAfterLockedSection
+ -D jack.transformations.boost-locked-region-priority.classname=com.android.server.am.ActivityManagerService,com.android.server.wm.WindowHashMap \
+ -D jack.transformations.boost-locked-region-priority.request=com.android.server.am.ActivityManagerService\#boostPriorityForLockedSection,com.android.server.wm.WindowManagerService\#boostPriorityForLockedSection \
+ -D jack.transformations.boost-locked-region-priority.reset=com.android.server.am.ActivityManagerService\#resetPriorityAfterLockedSection,com.android.server.wm.WindowManagerService\#resetPriorityAfterLockedSection
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/ThreadPriorityBooster.java b/services/core/java/com/android/server/ThreadPriorityBooster.java
new file mode 100644
index 0000000..17965d0
--- /dev/null
+++ b/services/core/java/com/android/server/ThreadPriorityBooster.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import android.os.Process;
+
+/**
+ * Utility class to boost threads in sections where important locks are held.
+ */
+public class ThreadPriorityBooster {
+
+    private final int mBoostToPriority;
+    private final int mLockGuardIndex;
+
+    private final ThreadLocal<PriorityState> mThreadState = new ThreadLocal<PriorityState>() {
+        @Override protected PriorityState initialValue() {
+            return new PriorityState();
+        }
+    };
+
+    public ThreadPriorityBooster(int boostToPriority, int lockGuardIndex) {
+        mBoostToPriority = boostToPriority;
+        mLockGuardIndex = lockGuardIndex;
+    }
+
+    public void boost() {
+        final int tid = Process.myTid();
+        final int prevPriority = Process.getThreadPriority(tid);
+        PriorityState state = mThreadState.get();
+        if (state.regionCounter == 0 && prevPriority > mBoostToPriority) {
+            state.prevPriority = prevPriority;
+            Process.setThreadPriority(tid, mBoostToPriority);
+        }
+        state.regionCounter++;
+        if (LockGuard.ENABLED) {
+            LockGuard.guard(mLockGuardIndex);
+        }
+    }
+
+    public void reset() {
+        PriorityState state = mThreadState.get();
+        state.regionCounter--;
+        if (state.regionCounter == 0 && state.prevPriority > mBoostToPriority) {
+            Process.setThreadPriority(Process.myTid(), state.prevPriority);
+        }
+    }
+
+    private static class PriorityState {
+
+        /**
+         * Acts as counter for number of synchronized region that needs to acquire 'this' as a lock
+         * the current thread is currently in. When it drops down to zero, we will no longer boost
+         * the thread's priority.
+         */
+        int regionCounter;
+
+        /**
+         * The thread's previous priority before boosting.
+         */
+        int prevPriority;
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4c747a1..19fc2b8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17,12 +17,12 @@
 package com.android.server.am;
 
 import static android.Manifest.permission.CHANGE_CONFIGURATION;
+import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -42,13 +42,49 @@
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
 import static android.os.Build.VERSION_CODES.N;
+import static android.os.Process.BLUETOOTH_UID;
+import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.Process.FIRST_ISOLATED_UID;
+import static android.os.Process.LAST_ISOLATED_UID;
+import static android.os.Process.NFC_UID;
+import static android.os.Process.PHONE_UID;
 import static android.os.Process.PROC_CHAR;
 import static android.os.Process.PROC_OUT_LONG;
 import static android.os.Process.PROC_PARENS;
 import static android.os.Process.PROC_SPACE_TERM;
-import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
-import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
+import static android.os.Process.ProcessStartResult;
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SCHED_FIFO;
+import static android.os.Process.SCHED_OTHER;
+import static android.os.Process.SCHED_RESET_ON_FORK;
+import static android.os.Process.SHELL_UID;
+import static android.os.Process.SIGNAL_QUIT;
+import static android.os.Process.SIGNAL_USR1;
+import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.THREAD_GROUP_BG_NONINTERACTIVE;
+import static android.os.Process.THREAD_GROUP_DEFAULT;
+import static android.os.Process.THREAD_GROUP_TOP_APP;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
+import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
+import static android.os.Process.getFreeMemory;
+import static android.os.Process.getThreadPriority;
+import static android.os.Process.getTotalMemory;
+import static android.os.Process.isThreadInProcess;
+import static android.os.Process.killProcess;
+import static android.os.Process.killProcessQuiet;
+import static android.os.Process.myPid;
+import static android.os.Process.myUid;
+import static android.os.Process.readProcFile;
+import static android.os.Process.removeAllProcessGroups;
+import static android.os.Process.sendSignal;
+import static android.os.Process.setProcessGroup;
+import static android.os.Process.setThreadPriority;
+import static android.os.Process.setThreadScheduler;
+import static android.os.Process.startWebView;
+import static android.os.Process.zygoteProcess;
 import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
 import static android.provider.Settings.Global.DEBUG_APP;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
@@ -323,7 +359,6 @@
 import android.view.View;
 import android.view.WindowManager;
 
-import com.android.internal.notification.SystemNotificationChannels;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -341,6 +376,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.IResultReceiver;
@@ -367,6 +403,7 @@
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
+import com.android.server.ThreadPriorityBooster;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.firewall.IntentFirewall;
@@ -409,7 +446,6 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 import dalvik.system.VMRuntime;
-
 import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 
@@ -547,7 +583,7 @@
     // Maximum number of persisted Uri grants a package is allowed
     static final int MAX_PERSISTED_URI_GRANTS = 128;
 
-    static final int MY_PID = Process.myPid();
+    static final int MY_PID = myPid();
 
     static final String[] EMPTY_STRING_ARRAY = new String[0];
 
@@ -680,13 +716,13 @@
                     if (mTopAppVrThreadTid > 0) {
                         // Ensure that when entering persistent VR mode the last top-app loses
                         // SCHED_FIFO.
-                        Process.setThreadScheduler(mTopAppVrThreadTid, Process.SCHED_OTHER, 0);
+                        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.
-                    Process.setThreadScheduler(mPersistentVrThreadTid, Process.SCHED_OTHER, 0);
+                    setThreadScheduler(mPersistentVrThreadTid, SCHED_OTHER, 0);
                     mPersistentVrThreadTid = 0;
                 }
             }
@@ -773,42 +809,15 @@
                 && !mKeyguardController.isKeyguardShowing();
     }
 
-    private static final class PriorityState {
-        // Acts as counter for number of synchronized region that needs to acquire 'this' as a lock
-        // the current thread is currently in. When it drops down to zero, we will no longer boost
-        // the thread's priority.
-        private int regionCounter = 0;
-
-        // The thread's previous priority before boosting.
-        private int prevPriority = Integer.MIN_VALUE;
-    }
-
-    static ThreadLocal<PriorityState> sThreadPriorityState = new ThreadLocal<PriorityState>() {
-        @Override protected PriorityState initialValue() {
-            return new PriorityState();
-        }
-    };
+    private static ThreadPriorityBooster sThreadPriorityBooster = new ThreadPriorityBooster(
+            THREAD_PRIORITY_FOREGROUND, LockGuard.INDEX_ACTIVITY);
 
     static void boostPriorityForLockedSection() {
-        int tid = Process.myTid();
-        int prevPriority = Process.getThreadPriority(tid);
-        PriorityState state = sThreadPriorityState.get();
-        if (state.regionCounter == 0 && prevPriority > -2) {
-            state.prevPriority = prevPriority;
-            Process.setThreadPriority(tid, -2);
-        }
-        state.regionCounter++;
-        if (LockGuard.ENABLED) {
-            LockGuard.guard(LockGuard.INDEX_ACTIVITY);
-        }
+        sThreadPriorityBooster.boost();
     }
 
     static void resetPriorityAfterLockedSection() {
-        PriorityState state = sThreadPriorityState.get();
-        state.regionCounter--;
-        if (state.regionCounter == 0 && state.prevPriority > -2) {
-            Process.setThreadPriority(Process.myTid(), state.prevPriority);
-        }
+        sThreadPriorityBooster.reset();
     }
 
     public class PendingAssistExtras extends Binder implements Runnable {
@@ -889,7 +898,7 @@
      * Non-persistent app uid whitelist for background restrictions
      */
     int[] mBackgroundUidWhitelist = new int[] {
-            Process.BLUETOOTH_UID
+            BLUETOOTH_UID
     };
 
     /**
@@ -2467,12 +2476,12 @@
                                 if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                                     try {
                                         if (mVrState == VR_MODE) {
-                                            Process.setThreadScheduler(proc.vrThreadTid,
-                                                Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                                            setThreadScheduler(proc.vrThreadTid,
+                                                SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                             mTopAppVrThreadTid = proc.vrThreadTid;
                                         } else {
-                                            Process.setThreadScheduler(proc.vrThreadTid,
-                                                Process.SCHED_OTHER, 0);
+                                            setThreadScheduler(proc.vrThreadTid,
+                                                SCHED_OTHER, 0);
                                             mTopAppVrThreadTid = 0;
                                         }
                                     } catch (IllegalArgumentException e) {
@@ -2529,7 +2538,7 @@
                     final List<ProcessCpuTracker.Stats> stats;
                     synchronized (mProcessCpuTracker) {
                         stats = mProcessCpuTracker.getStats( (st)-> {
-                            return st.vsize > 0 && st.uid < Process.FIRST_APPLICATION_UID;
+                            return st.vsize > 0 && st.uid < FIRST_APPLICATION_UID;
                         });
                     }
                     final int N = stats.size();
@@ -2780,7 +2789,7 @@
                 com.android.internal.R.bool.config_permissionReviewRequired);
 
         mHandlerThread = new ServiceThread(TAG,
-                android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
+                THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
         mHandlerThread.start();
         mHandler = new MainHandler(mHandlerThread.getLooper());
         mUiHandler = mInjector.getUiHandler(this);
@@ -2801,7 +2810,7 @@
         /* static; one-time init here */
         if (sKillHandler == null) {
             sKillThread = new ServiceThread(TAG + ":kill",
-                    android.os.Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
+                    THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
             sKillThread.start();
             sKillHandler = new KillHandler(sKillThread.getLooper());
         }
@@ -2919,7 +2928,7 @@
     }
 
     private void start() {
-        Process.removeAllProcessGroups();
+        removeAllProcessGroups();
         mProcessCpuThread.start();
 
         mBatteryStatsService.publish(mContext);
@@ -3127,7 +3136,7 @@
         synchronized (this) {
             broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
                     AppOpsManager.OP_NONE, null, false, false,
-                    -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
+                    -1, SYSTEM_UID, UserHandle.USER_ALL);
         }
     }
 
@@ -3399,7 +3408,7 @@
         if (lrui >= 0) {
             if (!app.killed) {
                 Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);
-                Process.killProcessQuiet(app.pid);
+                killProcessQuiet(app.pid);
                 killProcessGroup(app.uid, app.pid);
             }
             if (lrui <= mLruProcessActivityStart) {
@@ -3608,7 +3617,7 @@
     }
 
     final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
-        if (uid == Process.SYSTEM_UID) {
+        if (uid == SYSTEM_UID) {
             // The system gets to run in any process.  If there are multiple
             // processes with the same uid, just pick the first (this
             // should never happen).
@@ -3674,7 +3683,7 @@
             // closest thing to a parent's uid is SYSTEM_UID.
             // The only important thing here is to keep AI.uid != PR.uid, in order to trigger
             // the |isolated| logic in the ProcessRecord constructor.
-            info.uid = Process.SYSTEM_UID;
+            info.uid = SYSTEM_UID;
             info.processName = processName;
             info.className = entryPoint;
             info.packageName = "android";
@@ -3969,9 +3978,9 @@
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                     app.processName);
             checkTime(startTime, "startProcess: asking zygote to start proc");
-            Process.ProcessStartResult startResult;
+            ProcessStartResult startResult;
             if (hostingType.equals("webview_service")) {
-                startResult = Process.startWebView(entryPoint,
+                startResult = startWebView(entryPoint,
                         app.processName, uid, uid, gids, debugFlags, mountExternal,
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, null, entryPointArgs);
@@ -4208,7 +4217,7 @@
     }
 
     void enforceShellRestriction(String restriction, int userHandle) {
-        if (Binder.getCallingUid() == Process.SHELL_UID) {
+        if (Binder.getCallingUid() == SHELL_UID) {
             if (userHandle < 0 || mUserController.hasUserRestriction(restriction, userHandle)) {
                 throw new SecurityException("Shell does not have permission to access user "
                         + userHandle);
@@ -4574,7 +4583,7 @@
             if (sourceRecord.app == null) {
                 throw new SecurityException("Called without a process attached to activity");
             }
-            if (UserHandle.getAppId(sourceRecord.app.uid) != Process.SYSTEM_UID) {
+            if (UserHandle.getAppId(sourceRecord.app.uid) != SYSTEM_UID) {
                 // This is still okay, as long as this activity is running under the
                 // uid of the original calling activity.
                 if (sourceRecord.app.uid != sourceRecord.launchedFromUid) {
@@ -5426,7 +5435,7 @@
 
         if (!app.killed) {
             if (!fromBinderDied) {
-                Process.killProcessQuiet(pid);
+                killProcessQuiet(pid);
             }
             killProcessGroup(app.uid, pid);
             app.killed = true;
@@ -5521,7 +5530,7 @@
         }
 
         public void dumpWithTimeout(int pid) {
-            Process.sendSignal(pid, Process.SIGNAL_QUIT);
+            sendSignal(pid, SIGNAL_QUIT);
             synchronized (this) {
                 try {
                     wait(TRACE_DUMP_TIMEOUT_MS); // Wait for traces file to be closed.
@@ -5776,7 +5785,7 @@
                     intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                     intent.putExtra(Intent.EXTRA_UID, pkgUidF);
                     intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(pkgUidF));
-                    broadcastIntentInPackage("android", Process.SYSTEM_UID, intent,
+                    broadcastIntentInPackage("android", SYSTEM_UID, intent,
                             null, null, 0, null, null, null, null, false, false, userIdF);
 
                     if (observer != null) {
@@ -5994,7 +6003,7 @@
     public void addPackageDependency(String packageName) {
         synchronized (this) {
             int callingPid = Binder.getCallingPid();
-            if (callingPid == Process.myPid()) {
+            if (callingPid == myPid()) {
                 //  Yeah, um, no.
                 return;
             }
@@ -6026,7 +6035,7 @@
         }
         int callerUid = Binder.getCallingUid();
         // Only the system server can kill an application
-        if (UserHandle.getAppId(callerUid) == Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(callerUid) == SYSTEM_UID) {
             // Post an aysnc message to kill the application
             Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
             msg.arg1 = appId;
@@ -6053,7 +6062,7 @@
             synchronized (this) {
                 // Only allow this from foreground processes, so that background
                 // applications can't abuse it to prevent system UI from being shown.
-                if (uid >= Process.FIRST_APPLICATION_UID) {
+                if (uid >= FIRST_APPLICATION_UID) {
                     ProcessRecord proc;
                     synchronized (mPidsSelfLocked) {
                         proc = mPidsSelfLocked.get(pid);
@@ -6084,7 +6093,7 @@
 
         broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
                 AppOpsManager.OP_NONE, null, false, false,
-                -1, Process.SYSTEM_UID, UserHandle.USER_ALL);
+                -1, SYSTEM_UID, UserHandle.USER_ALL);
     }
 
     @Override
@@ -6150,7 +6159,7 @@
 
         int callerUid = Binder.getCallingUid();
         // Only the system server can kill an application
-        if (callerUid == Process.SYSTEM_UID) {
+        if (callerUid == SYSTEM_UID) {
             synchronized (this) {
                 ProcessRecord app = getProcessRecordLocked(processName, uid, true);
                 if (app != null && app.thread != null) {
@@ -6186,7 +6195,7 @@
         intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
         broadcastIntentLocked(null, null, intent,
                 null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid));
+                null, false, false, MY_PID, SYSTEM_UID, UserHandle.getUserId(uid));
     }
 
 
@@ -6703,7 +6712,7 @@
                     + " (IApplicationThread " + thread + "); dropping process");
             EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
             if (pid > 0 && pid != MY_PID) {
-                Process.killProcessQuiet(pid);
+                killProcessQuiet(pid);
                 //TODO: killProcessGroup(app.info.uid, pid);
             } else {
                 try {
@@ -6811,7 +6820,7 @@
             // If the app is being launched for restore or full backup, set it up specially
             boolean isRestrictedBackupMode = false;
             if (mBackupTarget != null && mBackupAppName.equals(processName)) {
-                isRestrictedBackupMode = mBackupTarget.appInfo.uid >= Process.FIRST_APPLICATION_UID
+                isRestrictedBackupMode = mBackupTarget.appInfo.uid >= FIRST_APPLICATION_UID
                         && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
                                 || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
                                 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
@@ -7034,7 +7043,7 @@
 
     @Override
     public void showBootMessage(final CharSequence msg, final boolean always) {
-        if (Binder.getCallingUid() != Process.myUid()) {
+        if (Binder.getCallingUid() != myUid()) {
             throw new SecurityException();
         }
         mWindowManager.showBootMessage(msg, always);
@@ -7071,7 +7080,7 @@
 
         ArraySet<String> completedIsas = new ArraySet<String>();
         for (String abi : Build.SUPPORTED_ABIS) {
-            Process.zygoteProcess.establishZygoteConnectionForAbi(abi);
+            zygoteProcess.establishZygoteConnectionForAbi(abi);
             final String instructionSet = VMRuntime.getInstructionSet(abi);
             if (!completedIsas.contains(instructionSet)) {
                 try {
@@ -7412,7 +7421,7 @@
                 userId = UserHandle.USER_CURRENT;
             }
             try {
-                if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+                if (callingUid != 0 && callingUid != SYSTEM_UID) {
                     final int uid = AppGlobals.getPackageManager().getPackageUid(packageName,
                             MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callingUid));
                     if (!UserHandle.isSameApp(callingUid, uid)) {
@@ -8679,7 +8688,7 @@
         // Third...  does the caller itself have permission to access
         // this uri?
         final int callingAppId = UserHandle.getAppId(callingUid);
-        if ((callingAppId == Process.SYSTEM_UID) || (callingAppId == Process.ROOT_UID)) {
+        if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {
             if ("com.android.settings.files".equals(grantUri.uri.getAuthority())) {
                 // Exempted authority for cropping user photos in Settings app
             } else {
@@ -9165,7 +9174,7 @@
                 throw new IllegalArgumentException("Unknown owner: " + token);
             }
             if (fromUid != Binder.getCallingUid()) {
-                if (Binder.getCallingUid() != Process.myUid()) {
+                if (Binder.getCallingUid() != myUid()) {
                     // Only system code can grant URI permissions on behalf
                     // of other users.
                     throw new SecurityException("nice try");
@@ -9549,8 +9558,8 @@
     public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
         final long homeAppMem = mProcessList.getMemLevel(ProcessList.HOME_APP_ADJ);
         final long cachedAppMem = mProcessList.getMemLevel(ProcessList.CACHED_APP_MIN_ADJ);
-        outInfo.availMem = Process.getFreeMemory();
-        outInfo.totalMem = Process.getTotalMemory();
+        outInfo.availMem = getFreeMemory();
+        outInfo.totalMem = getTotalMemory();
         outInfo.threshold = homeAppMem;
         outInfo.lowMemory = outInfo.availMem < (homeAppMem + ((cachedAppMem-homeAppMem)/2));
         outInfo.hiddenAppThreshold = cachedAppMem;
@@ -10693,7 +10702,7 @@
     @Override
     public void updateDeviceOwner(String packageName) {
         final int callingUid = Binder.getCallingUid();
-        if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+        if (callingUid != 0 && callingUid != SYSTEM_UID) {
             throw new SecurityException("updateDeviceOwner called from non-system process");
         }
         synchronized (this) {
@@ -10704,7 +10713,7 @@
     @Override
     public void updateLockTaskPackages(int userId, String[] packages) {
         final int callingUid = Binder.getCallingUid();
-        if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
+        if (callingUid != 0 && callingUid != SYSTEM_UID) {
             enforceCallingPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES,
                     "updateLockTaskPackages()");
         }
@@ -10727,7 +10736,7 @@
         // is initiated by system after the pinning request was shown and locked mode is initiated
         // by an authorized app directly
         final int callingUid = Binder.getCallingUid();
-        boolean isSystemInitiated = callingUid == Process.SYSTEM_UID;
+        boolean isSystemInitiated = callingUid == SYSTEM_UID;
         long ident = Binder.clearCallingIdentity();
         try {
             if (!isSystemInitiated) {
@@ -11206,7 +11215,7 @@
             proc.procStatFile = "/proc/" + proc.pid + "/stat";
         }
         mProcessStateStatsLongs[0] = 0;
-        if (!Process.readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
+        if (!readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
                 mProcessStateStatsLongs, null)) {
             if (DEBUG_OOM_ADJ) Slog.d(TAG, "UNABLE TO RETRIEVE STATE FOR " + proc.procStatFile);
             return false;
@@ -11908,7 +11917,7 @@
     public final void installSystemProviders() {
         List<ProviderInfo> providers;
         synchronized (this) {
-            ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);
+            ProcessRecord app = mProcessNames.get("system", SYSTEM_UID);
             providers = generateApplicationProvidersLocked(app);
             if (providers != null) {
                 for (int i=providers.size()-1; i>=0; i--) {
@@ -12081,11 +12090,11 @@
         int uid = info.uid;
         if (isolated) {
             if (isolatedUid == 0) {
-                int stepsLeft = Process.LAST_ISOLATED_UID - Process.FIRST_ISOLATED_UID + 1;
+                int stepsLeft = LAST_ISOLATED_UID - FIRST_ISOLATED_UID + 1;
                 while (true) {
-                    if (mNextIsolatedProcessUid < Process.FIRST_ISOLATED_UID
-                            || mNextIsolatedProcessUid > Process.LAST_ISOLATED_UID) {
-                        mNextIsolatedProcessUid = Process.FIRST_ISOLATED_UID;
+                    if (mNextIsolatedProcessUid < FIRST_ISOLATED_UID
+                            || mNextIsolatedProcessUid > LAST_ISOLATED_UID) {
+                        mNextIsolatedProcessUid = FIRST_ISOLATED_UID;
                     }
                     uid = UserHandle.getUid(userId, mNextIsolatedProcessUid);
                     mNextIsolatedProcessUid++;
@@ -13274,7 +13283,7 @@
         synchronized (this) {
             // Disable any existing VR thread.
             if (mTopAppVrThreadTid > 0) {
-                Process.setThreadScheduler(mTopAppVrThreadTid, Process.SCHED_OTHER, 0);
+                setThreadScheduler(mTopAppVrThreadTid, SCHED_OTHER, 0);
                 mTopAppVrThreadTid = 0;
             }
 
@@ -13298,15 +13307,15 @@
      */
     private int updateVrThreadLocked(ProcessRecord proc, int lastTid, int pid, int tid) {
         // ensure the tid belongs to the process
-        if (!Process.isThreadInProcess(pid, tid)) {
+        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 && Process.isThreadInProcess(pid, lastTid)) {
+        if (lastTid != 0 && isThreadInProcess(pid, lastTid)) {
             try {
-                Process.setThreadScheduler(lastTid, Process.SCHED_OTHER, 0);
+                setThreadScheduler(lastTid, SCHED_OTHER, 0);
             } catch (IllegalArgumentException e) {
                 // Ignore this.  Only occurs in race condition where previous VR thread
                 // was destroyed during this method call.
@@ -13317,8 +13326,8 @@
         try {
             if ((proc == null || proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP)
                     && tid > 0) {
-                Process.setThreadScheduler(tid,
-                    Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                setThreadScheduler(tid,
+                    SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
             }
             return tid;
         } catch (IllegalArgumentException e) {
@@ -13337,7 +13346,7 @@
                 proc = mPidsSelfLocked.get(pid);
                 if (proc != null && proc.renderThreadTid == 0 && tid > 0) {
                     // ensure the tid belongs to the process
-                    if (!Process.isThreadInProcess(pid, tid)) {
+                    if (!isThreadInProcess(pid, tid)) {
                         throw new IllegalArgumentException(
                             "Render thread does not belong to process");
                     }
@@ -13349,10 +13358,10 @@
                     if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                         if (DEBUG_OOM_ADJ) Slog.d("UI_FIFO", "Promoting " + tid + "out of band");
                         if (mUseFifoUiScheduling) {
-                            Process.setThreadScheduler(proc.renderThreadTid,
-                                Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                            setThreadScheduler(proc.renderThreadTid,
+                                SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                         } else {
-                            Process.setThreadPriority(proc.renderThreadTid, -10);
+                            setThreadPriority(proc.renderThreadTid, -10);
                         }
                     }
                 } else {
@@ -13513,7 +13522,7 @@
                 if (sender == null) {
                     uid = sourceUid;
                 } else {
-                    uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+                    uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
                 }
                 BatteryStatsImpl.Uid.Pkg pkg =
                     stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
@@ -13536,7 +13545,7 @@
             if (sender == null) {
                 uid = sourceUid;
             } else {
-                uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+                uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
             }
             mBatteryStatsService.noteAlarmStart(tag, sourceUid >= 0 ? sourceUid : uid);
         }
@@ -13555,14 +13564,14 @@
             if (sender == null) {
                 uid = sourceUid;
             } else {
-                uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+                uid = rec.uid == MY_UID ? SYSTEM_UID : rec.uid;
             }
             mBatteryStatsService.noteAlarmFinish(tag, sourceUid >= 0 ? sourceUid : uid);
         }
     }
 
     public boolean killPids(int[] pids, String pReason, boolean secure) {
-        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+        if (Binder.getCallingUid() != SYSTEM_UID) {
             throw new SecurityException("killPids only available to the system");
         }
         String reason = (pReason == null) ? "Unknown" : pReason;
@@ -13628,7 +13637,7 @@
 
     @Override
     public boolean killProcessesBelowForeground(String reason) {
-        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+        if (Binder.getCallingUid() != SYSTEM_UID) {
             throw new SecurityException("killProcessesBelowForeground() only available to system");
         }
 
@@ -13636,7 +13645,7 @@
     }
 
     private boolean killProcessesBelowAdj(int belowAdj, String reason) {
-        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+        if (Binder.getCallingUid() != SYSTEM_UID) {
             throw new SecurityException("killProcessesBelowAdj() only available to system");
         }
 
@@ -13713,7 +13722,7 @@
                 Log.i(TAG, "Shutting down activity manager...");
                 shutdown(10000);
                 Log.i(TAG, "Shutdown complete, restarting!");
-                Process.killProcess(Process.myPid());
+                killProcess(myPid());
                 System.exit(10);
             }
         };
@@ -14057,7 +14066,7 @@
                 intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
                 broadcastIntentLocked(null, null, intent,
                         null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                        null, false, false, MY_PID, Process.SYSTEM_UID,
+                        null, false, false, MY_PID, SYSTEM_UID,
                         currentUserId);
                 intent = new Intent(Intent.ACTION_USER_STARTING);
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -14071,7 +14080,7 @@
                             }
                         }, 0, null, null,
                         new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
-                        null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+                        null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
             } catch (Throwable t) {
                 Slog.wtf(TAG, "Failed sending first user broadcasts", t);
             } finally {
@@ -16716,22 +16725,22 @@
     private final long[] getKsmInfo() {
         long[] longOut = new long[4];
         final int[] SINGLE_LONG_FORMAT = new int[] {
-            Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
+            PROC_SPACE_TERM| PROC_OUT_LONG
         };
         long[] longTmp = new long[1];
-        Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
+        readProcFile("/sys/kernel/mm/ksm/pages_shared",
                 SINGLE_LONG_FORMAT, null, longTmp, null);
         longOut[KSM_SHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
         longTmp[0] = 0;
-        Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
+        readProcFile("/sys/kernel/mm/ksm/pages_sharing",
                 SINGLE_LONG_FORMAT, null, longTmp, null);
         longOut[KSM_SHARING] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
         longTmp[0] = 0;
-        Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
+        readProcFile("/sys/kernel/mm/ksm/pages_unshared",
                 SINGLE_LONG_FORMAT, null, longTmp, null);
         longOut[KSM_UNSHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
         longTmp[0] = 0;
-        Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
+        readProcFile("/sys/kernel/mm/ksm/pages_volatile",
                 SINGLE_LONG_FORMAT, null, longTmp, null);
         longOut[KSM_VOLATILE] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
         return longOut;
@@ -18007,7 +18016,7 @@
             String className, int flags) {
         boolean result = false;
         // For apps that don't have pre-defined UIDs, check for permission
-        if (UserHandle.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
+        if (UserHandle.getAppId(aInfo.uid) >= FIRST_APPLICATION_UID) {
             if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
                 if (ActivityManager.checkUidPermission(
                         INTERACT_ACROSS_USERS,
@@ -18026,7 +18035,7 @@
             result = true;
         } else if ((flags & ServiceInfo.FLAG_SINGLE_USER) != 0) {
             // Phone app and persistent apps are allowed to export singleuser providers.
-            result = UserHandle.isSameApp(aInfo.uid, Process.PHONE_UID)
+            result = UserHandle.isSameApp(aInfo.uid, PHONE_UID)
                     || (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
         }
         if (DEBUG_MU) Slog.v(TAG_MU,
@@ -18044,8 +18053,8 @@
     boolean isValidSingletonCall(int callingUid, int componentUid) {
         int componentAppId = UserHandle.getAppId(componentUid);
         return UserHandle.isSameApp(callingUid, componentUid)
-                || componentAppId == Process.SYSTEM_UID
-                || componentAppId == Process.PHONE_UID
+                || componentAppId == SYSTEM_UID
+                || componentAppId == PHONE_UID
                 || ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, componentUid)
                         == PackageManager.PERMISSION_GRANTED;
     }
@@ -18286,7 +18295,7 @@
     // =========================================================
 
     private boolean isInstantApp(ProcessRecord record, String callerPackage, int uid) {
-        if (UserHandle.getAppId(uid) < Process.FIRST_APPLICATION_UID) {
+        if (UserHandle.getAppId(uid) < FIRST_APPLICATION_UID) {
             return false;
         }
         // Easy case -- we have the app's ProcessRecord.
@@ -18347,7 +18356,7 @@
                             + " (pid=" + Binder.getCallingPid()
                             + ") when registering receiver " + receiver);
                 }
-                if (callerApp.info.uid != Process.SYSTEM_UID &&
+                if (callerApp.info.uid != SYSTEM_UID &&
                         !callerApp.pkgList.containsKey(callerPackage) &&
                         !"android".equals(callerPackage)) {
                     throw new SecurityException("Given caller package " + callerPackage
@@ -18564,7 +18573,7 @@
             for (int user : users) {
                 // Skip users that have Shell restrictions, with exception of always permitted
                 // Shell broadcasts
-                if (callingUid == Process.SHELL_UID
+                if (callingUid == SHELL_UID
                         && mUserController.hasUserRestriction(
                                 UserManager.DISALLOW_DEBUGGING_FEATURES, user)
                         && !isPermittedShellBroadcast(intent)) {
@@ -18748,7 +18757,7 @@
         // and upgrade steps.
 
         if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, 0)) {
-            if ((callingUid != Process.SYSTEM_UID
+            if ((callingUid != SYSTEM_UID
                     || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
                     && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
                 Slog.w(TAG, "Skipping broadcast of " + intent
@@ -18792,11 +18801,11 @@
 
         final boolean isCallerSystem;
         switch (UserHandle.getAppId(callingUid)) {
-            case Process.ROOT_UID:
-            case Process.SYSTEM_UID:
-            case Process.PHONE_UID:
-            case Process.BLUETOOTH_UID:
-            case Process.NFC_UID:
+            case ROOT_UID:
+            case SYSTEM_UID:
+            case PHONE_UID:
+            case BLUETOOTH_UID:
+            case NFC_UID:
                 isCallerSystem = true;
                 break;
             default:
@@ -19172,7 +19181,7 @@
             receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
         }
         if (intent.getComponent() == null) {
-            if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
+            if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
                 // Query one target user at a time, excluding shell-restricted users
                 for (int i = 0; i < users.length; i++) {
                     if (mUserController.hasUserRestriction(
@@ -19414,8 +19423,8 @@
 
         if ((flags & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
             switch (Binder.getCallingUid()) {
-                case Process.ROOT_UID:
-                case Process.SHELL_UID:
+                case ROOT_UID:
+                case SHELL_UID:
                     break;
                 default:
                     Slog.w(TAG, "Removing FLAG_RECEIVER_FROM_SHELL because caller is UID "
@@ -19870,7 +19879,7 @@
 
     private void enforceWriteSettingsPermission(String func) {
         int uid = Binder.getCallingUid();
-        if (uid == Process.ROOT_UID) {
+        if (uid == ROOT_UID) {
             return;
         }
 
@@ -20068,7 +20077,7 @@
                 | Intent.FLAG_RECEIVER_FOREGROUND
                 | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
         broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
+                AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
                 UserHandle.USER_ALL);
         if ((changes & ActivityInfo.CONFIG_LOCALE) != 0) {
             intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
@@ -20079,7 +20088,7 @@
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
             }
             broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
-                    AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
+                    AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
                     UserHandle.USER_ALL);
         }
 
@@ -21553,27 +21562,27 @@
                 int processGroup;
                 switch (app.curSchedGroup) {
                     case ProcessList.SCHED_GROUP_BACKGROUND:
-                        processGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                        processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
                         break;
                     case ProcessList.SCHED_GROUP_TOP_APP:
                     case ProcessList.SCHED_GROUP_TOP_APP_BOUND:
-                        processGroup = Process.THREAD_GROUP_TOP_APP;
+                        processGroup = THREAD_GROUP_TOP_APP;
                         break;
                     default:
-                        processGroup = Process.THREAD_GROUP_DEFAULT;
+                        processGroup = THREAD_GROUP_DEFAULT;
                         break;
                 }
                 long oldId = Binder.clearCallingIdentity();
                 try {
-                    Process.setProcessGroup(app.pid, processGroup);
+                    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 (mVrState == VR_MODE && app.vrThreadTid != 0) {
                                 try {
-                                    Process.setThreadScheduler(app.vrThreadTid,
-                                        Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                                    setThreadScheduler(app.vrThreadTid,
+                                        SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                     mTopAppVrThreadTid = app.vrThreadTid;
                                 } catch (IllegalArgumentException e) {
                                     // thread died, ignore
@@ -21581,17 +21590,17 @@
                             }
                             if (mUseFifoUiScheduling) {
                                 // Switch UI pipeline for app to SCHED_FIFO
-                                app.savedPriority = Process.getThreadPriority(app.pid);
+                                app.savedPriority = getThreadPriority(app.pid);
                                 try {
-                                    Process.setThreadScheduler(app.pid,
-                                        Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                                    setThreadScheduler(app.pid,
+                                        SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                 } catch (IllegalArgumentException e) {
                                     // thread died, ignore
                                 }
                                 if (app.renderThreadTid != 0) {
                                     try {
-                                        Process.setThreadScheduler(app.renderThreadTid,
-                                            Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);
+                                        setThreadScheduler(app.renderThreadTid,
+                                            SCHED_FIFO | SCHED_RESET_ON_FORK, 1);
                                     } catch (IllegalArgumentException e) {
                                         // thread died, ignore
                                     }
@@ -21606,10 +21615,10 @@
                                 }
                             } else {
                                 // Boost priority for top app UI and render threads
-                                Process.setThreadPriority(app.pid, -10);
+                                setThreadPriority(app.pid, -10);
                                 if (app.renderThreadTid != 0) {
                                     try {
-                                        Process.setThreadPriority(app.renderThreadTid, -10);
+                                        setThreadPriority(app.renderThreadTid, -10);
                                     } catch (IllegalArgumentException e) {
                                         // thread died, ignore
                                     }
@@ -21621,23 +21630,23 @@
                         // 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);
+                            setThreadScheduler(app.vrThreadTid, SCHED_OTHER, 0);
                             mTopAppVrThreadTid = 0;
                         }
                         if (mUseFifoUiScheduling) {
                             // Reset UI pipeline to SCHED_OTHER
-                            Process.setThreadScheduler(app.pid, Process.SCHED_OTHER, 0);
-                            Process.setThreadPriority(app.pid, app.savedPriority);
+                            setThreadScheduler(app.pid, SCHED_OTHER, 0);
+                            setThreadPriority(app.pid, app.savedPriority);
                             if (app.renderThreadTid != 0) {
-                                Process.setThreadScheduler(app.renderThreadTid,
-                                    Process.SCHED_OTHER, 0);
-                                Process.setThreadPriority(app.renderThreadTid, -4);
+                                setThreadScheduler(app.renderThreadTid,
+                                    SCHED_OTHER, 0);
+                                setThreadPriority(app.renderThreadTid, -4);
                             }
                         } else {
                             // Reset priority for top app UI and render threads
-                            Process.setThreadPriority(app.pid, 0);
+                            setThreadPriority(app.pid, 0);
                             if (app.renderThreadTid != 0) {
-                                Process.setThreadPriority(app.renderThreadTid, 0);
+                                setThreadPriority(app.renderThreadTid, 0);
                             }
                         }
                     }
@@ -22747,7 +22756,7 @@
 
     /** This method sends the specified signal to each of the persistent apps */
     public void signalPersistentProcesses(int sig) throws RemoteException {
-        if (sig != Process.SIGNAL_USR1) {
+        if (sig != SIGNAL_USR1) {
             throw new SecurityException("Only SIGNAL_USR1 is allowed");
         }
 
@@ -22761,7 +22770,7 @@
             for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
                 ProcessRecord r = mLruProcesses.get(i);
                 if (r.thread != null && r.persistent) {
-                    Process.sendSignal(r.pid, sig);
+                    sendSignal(r.pid, sig);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowContainerController.java b/services/core/java/com/android/server/wm/WindowContainerController.java
index 84ffc35..c4a6837 100644
--- a/services/core/java/com/android/server/wm/WindowContainerController.java
+++ b/services/core/java/com/android/server/wm/WindowContainerController.java
@@ -33,7 +33,7 @@
 
     final WindowManagerService mService;
     final RootWindowContainer mRoot;
-    final HashMap<IBinder, WindowState> mWindowMap;
+    final WindowHashMap mWindowMap;
 
     // The window container this controller owns.
     E mContainer;
diff --git a/services/core/java/com/android/server/wm/WindowHashMap.java b/services/core/java/com/android/server/wm/WindowHashMap.java
new file mode 100644
index 0000000..49bba41
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowHashMap.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm;
+
+import android.os.IBinder;
+
+import java.util.HashMap;
+
+/**
+ * Subclass of HashMap such that we can instruct the compiler to boost our thread priority when
+ * locking this class. See makefile.
+ */
+class WindowHashMap extends HashMap<IBinder, WindowState> {
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f1796de..1be0512 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.Manifest.permission.MANAGE_APP_TOKENS;
+import static android.Manifest.permission.READ_FRAME_BUFFER;
 import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
@@ -25,6 +26,11 @@
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.Intent.EXTRA_USER_HANDLE;
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SHELL_UID;
+import static android.os.Process.SYSTEM_UID;
+import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+import static android.os.Process.myPid;
 import static android.os.UserHandle.USER_NULL;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.DOCKED_INVALID;
@@ -60,6 +66,8 @@
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.LockGuard.INDEX_WINDOW;
+import static com.android.server.LockGuard.installLock;
 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
@@ -125,7 +133,6 @@
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputManager;
 import android.net.Uri;
-import android.os.PowerSaveState;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -139,7 +146,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
-import android.os.Process;
+import android.os.PowerSaveState;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -151,10 +158,10 @@
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.ArraySet;
-import android.util.MergedConfiguration;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.MergedConfiguration;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -215,7 +222,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
-import com.android.server.LockGuard;
+import com.android.server.ThreadPriorityBooster;
 import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.input.InputManagerService;
@@ -239,10 +246,7 @@
 import java.text.DateFormat;
 import java.util.ArrayList;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.List;
-
-import static android.Manifest.permission.READ_FRAME_BUFFER;
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
         implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
@@ -408,7 +412,7 @@
      * This is also used as the lock for all of our state.
      * NOTE: Never call into methods that lock ActivityManagerService while holding this object.
      */
-    final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>();
+    final WindowHashMap mWindowMap = new WindowHashMap();
 
     /**
      * List of window tokens that have finished starting their application,
@@ -848,6 +852,16 @@
     // since they won't be notified through the app window animator.
     final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
 
+    private static ThreadPriorityBooster sThreadPriorityBooster = new ThreadPriorityBooster(
+            THREAD_PRIORITY_DISPLAY, INDEX_WINDOW);
+
+    static void boostPriorityForLockedSection() {
+        sThreadPriorityBooster.boost();
+    }
+
+    static void resetPriorityAfterLockedSection() {
+        sThreadPriorityBooster.reset();
+    }
 
     void openSurfaceTransaction() {
         synchronized (mWindowMap) {
@@ -936,7 +950,7 @@
     private WindowManagerService(Context context, InputManagerService inputManager,
             boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
             WindowManagerPolicy policy) {
-        LockGuard.installLock(this, LockGuard.INDEX_WINDOW);
+        installLock(this, INDEX_WINDOW);
         mRoot = new RootWindowContainer(this);
         mContext = context;
         mHaveInputMethods = haveInputMethods;
@@ -1581,7 +1595,7 @@
     @Override
     public void enableSurfaceTrace(ParcelFileDescriptor pfd) {
         final int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
+        if (callingUid != SHELL_UID && callingUid != ROOT_UID) {
             throw new SecurityException("Only shell can call enableSurfaceTrace");
         }
 
@@ -1593,8 +1607,8 @@
     @Override
     public void disableSurfaceTrace() {
         final int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID &&
-            callingUid != Process.SYSTEM_UID) {
+        if (callingUid != SHELL_UID && callingUid != ROOT_UID &&
+            callingUid != SYSTEM_UID) {
             throw new SecurityException("Only shell can call disableSurfaceTrace");
         }
         synchronized (mWindowMap) {
@@ -1608,7 +1622,7 @@
     @Override
     public void setScreenCaptureDisabled(int userId, boolean disabled) {
         int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.SYSTEM_UID) {
+        if (callingUid != SYSTEM_UID) {
             throw new SecurityException("Only system can call setScreenCaptureDisabled.");
         }
 
@@ -2264,7 +2278,7 @@
 
     boolean checkCallingPermission(String permission, String func) {
         // Quick check: if the calling permission is me, it's all okay.
-        if (Binder.getCallingPid() == Process.myPid()) {
+        if (Binder.getCallingPid() == myPid()) {
             return true;
         }
 
@@ -2917,7 +2931,7 @@
         }
         // If this isn't coming from the system then don't allow disabling the lockscreen
         // to bypass security.
-        if (Binder.getCallingUid() != Process.SYSTEM_UID && isKeyguardSecure()) {
+        if (Binder.getCallingUid() != SYSTEM_UID && isKeyguardSecure()) {
             Log.d(TAG_WM, "current mode is SecurityMode, ignore disableKeyguard");
             return;
         }
@@ -7058,7 +7072,7 @@
                     throw new IllegalStateException("Magnification callbacks not set!");
                 }
             }
-            if (Binder.getCallingPid() != android.os.Process.myPid()) {
+            if (Binder.getCallingPid() != myPid()) {
                 spec.recycle();
             }
         }
diff --git a/tests/WindowManagerStressTest/Android.mk b/tests/WindowManagerStressTest/Android.mk
new file mode 100644
index 0000000..e4cbe93
--- /dev/null
+++ b/tests/WindowManagerStressTest/Android.mk
@@ -0,0 +1,26 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := WindowManagerStressTest
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/WindowManagerStressTest/AndroidManifest.xml b/tests/WindowManagerStressTest/AndroidManifest.xml
new file mode 100644
index 0000000..17e0f15
--- /dev/null
+++ b/tests/WindowManagerStressTest/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="test.windowmanagerstresstest">
+
+    <application
+        android:allowBackup="false"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity android:name=".MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/WindowManagerStressTest/res/layout/activity_main.xml b/tests/WindowManagerStressTest/res/layout/activity_main.xml
new file mode 100644
index 0000000..6cf8269
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/layout/activity_main.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    tools:context="test.amslam.MainActivity">
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/run"
+        android:text="@string/run" />
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/output" />
+
+</LinearLayout>
diff --git a/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png b/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/WindowManagerStressTest/res/values/colors.xml b/tests/WindowManagerStressTest/res/values/colors.xml
new file mode 100644
index 0000000..4270ca6
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/values/colors.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/tests/WindowManagerStressTest/res/values/dimens.xml b/tests/WindowManagerStressTest/res/values/dimens.xml
new file mode 100644
index 0000000..ed4ccbc
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>
diff --git a/tests/WindowManagerStressTest/res/values/strings.xml b/tests/WindowManagerStressTest/res/values/strings.xml
new file mode 100644
index 0000000..cef05dc
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/values/strings.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <string name="app_name">WmSlam</string>
+    <string name="run">Run</string>
+</resources>
diff --git a/tests/WindowManagerStressTest/res/values/styles.xml b/tests/WindowManagerStressTest/res/values/styles.xml
new file mode 100644
index 0000000..0983b25
--- /dev/null
+++ b/tests/WindowManagerStressTest/res/values/styles.xml
@@ -0,0 +1,23 @@
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="android:colorPrimary">@color/colorPrimary</item>
+        <item name="android:colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="android:colorAccent">@color/colorAccent</item>
+    </style>
+</resources>
diff --git a/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
new file mode 100644
index 0000000..6b9bb31
--- /dev/null
+++ b/tests/WindowManagerStressTest/src/test/windowmanagerstresstest/MainActivity.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package test.windowmanagerstresstest;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.MergedConfiguration;
+import android.view.Display;
+import android.view.IWindowSession;
+import android.view.Surface;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerGlobal;
+import android.widget.TextView;
+
+import com.android.internal.view.BaseIWindow;
+
+import java.util.ArrayList;
+
+public class MainActivity extends Activity {
+
+    private static final String TAG = "WmSlam";
+
+    private TextView mOutput;
+    private volatile boolean finished;
+    private final ArrayList<BaseIWindow> mWindows = new ArrayList<>();
+    private final LayoutParams mLayoutParams = new LayoutParams();
+    private final Rect mTmpRect = new Rect();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        mOutput = (TextView) findViewById(R.id.output);
+
+        findViewById(R.id.run).setOnClickListener(view -> {
+            view.setEnabled(false);
+            mOutput.setText("");
+            startBatch();
+        });
+        mLayoutParams.token = getActivityToken();
+    }
+
+    void startBatch() {
+        new Thread(() -> {
+            finished = false;
+            addWindows();
+            startCpuRunnables();
+            for (int i = 0; i < 5; i++) {
+                final long time = SystemClock.uptimeMillis();
+                slamWm();
+                log("Total: " + (SystemClock.uptimeMillis() - time) + " ms");
+            }
+            removeWindows();
+            finished = true;
+        }).start();
+    }
+
+    void startCpuRunnables() {
+        for (int i = 0; i < 10; i++) {
+            new Thread(mUseCpuRunnable).start();
+        }
+    }
+
+    private final Runnable mUseCpuRunnable = new Runnable() {
+        @Override
+        public void run() {
+            while (!finished) {
+            }
+        }
+    };
+
+    private void log(String text) {
+        mOutput.post(() -> mOutput.append(text + "\n"));
+        Log.d(TAG, text);
+    }
+
+    private void slamWm() {
+        ArrayList<Thread> threads = new ArrayList<>();
+        for (int i = 0; i < 20; i++) {
+            for (BaseIWindow window : mWindows) {
+                Thread t = new Thread(() -> {
+                    try {
+                        WindowManagerGlobal.getWindowSession().relayout(window,
+                                window.mSeq, mLayoutParams, -1, -1, View.VISIBLE, 0, mTmpRect,
+                                mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect, mTmpRect,
+                                new MergedConfiguration(), new Surface());
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                });
+                threads.add(t);
+                t.start();
+            }
+        }
+        for (Thread t : threads) {
+            try {
+                t.join();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    void addWindows() {
+        for (int i = 0; i < 50; i++) {
+            final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+            layoutParams.token = getActivityToken();
+            final BaseIWindow window = new BaseIWindow();
+            final IWindowSession session = WindowManagerGlobal.getWindowSession();
+            final Rect tmpRect = new Rect();
+            try {
+                final int res = session.addToDisplayWithoutInputChannel(window, window.mSeq, layoutParams,
+                        View.VISIBLE, Display.DEFAULT_DISPLAY, tmpRect, tmpRect);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+            mWindows.add(window);
+        }
+    }
+
+    void removeWindows() {
+        for (BaseIWindow window : mWindows) {
+            try {
+                WindowManagerGlobal.getWindowSession().remove(window);
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}