Introduced WindowProcessController/Listener (10/n)

One heavy dependence between the current AMS service and activities
is process management which is heavy affected by activities and their
current state. We introduce WindowProcessController and WindowProcessListener
objects as a structured way for the process changes in AM package to
be communicated to the WM package and WindowProcessListner for activity
changes in the WM package to the communicated back to the AM package.
The ProcessRecord object in AM will own the WindowProcessController object
and also implement the WindowProcessListener.

Test: Existing tests pass
Test: go/wm-smoke-auto
Bug: 80414790
Change-Id: I9e96e841b0f95e99a597cb4629fa5d2fe45760b6
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 4e700d7..a34c2b9 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -19,7 +19,6 @@
 import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
 import android.app.AlarmManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -31,15 +30,15 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.database.ContentObserver;
 import android.hardware.Sensor;
-import android.hardware.SensorManager;
 import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
 import android.hardware.TriggerEvent;
 import android.hardware.TriggerEventListener;
-import android.location.LocationRequest;
 import android.location.Location;
 import android.location.LocationListener;
 import android.location.LocationManager;
+import android.location.LocationRequest;
 import android.net.ConnectivityManager;
 import android.net.INetworkPolicyManager;
 import android.net.NetworkInfo;
@@ -86,6 +85,7 @@
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index d025a87..92005d2 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -24,23 +24,18 @@
 import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
 import static android.os.storage.OnObbStateChangeListener.MOUNTED;
 import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
-
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
 import static com.android.internal.util.XmlUtils.readStringAttribute;
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.internal.util.XmlUtils.writeStringAttribute;
-
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
 import android.Manifest;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
-import android.app.ActivityTaskManagerInternal.ScreenObserver;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.app.KeyguardManager;
@@ -126,9 +121,8 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.storage.AppFuseBridge;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -164,6 +158,9 @@
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.PBEKeySpec;
 
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
 /**
  * Service responsible for various storage media. Connects to {@code vold} to
  * watch for and manage dynamically added storage, such as SD cards and USB mass
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 652bc6a..f7cd5ad 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1389,7 +1389,7 @@
     private boolean updateServiceClientActivitiesLocked(ProcessRecord proc,
             ConnectionRecord modCr, boolean updateLru) {
         if (modCr != null && modCr.binding.client != null) {
-            if (modCr.binding.client.activities.size() <= 0) {
+            if (!modCr.binding.client.hasActivities()) {
                 // This connection is from a client without activities, so adding
                 // and removing is not interesting.
                 return false;
@@ -1407,7 +1407,7 @@
                         // Binding to ourself is not interesting.
                         continue;
                     }
-                    if (cr.binding.client.activities.size() > 0) {
+                    if (cr.binding.client.hasActivities()) {
                         anyClientActivities = true;
                         break;
                     }
@@ -2081,7 +2081,7 @@
                 bumpServiceExecutingLocked(r, execInFg, "bind");
                 r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
-                        r.app.repProcState);
+                        r.app.getReportedProcState());
                 if (!rebind) {
                     i.requested = true;
                 }
@@ -2463,7 +2463,7 @@
             app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
             app.thread.scheduleCreateService(r, r.serviceInfo,
                     mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
-                    app.repProcState);
+                    app.getReportedProcState());
             r.postNotification();
             created = true;
         } catch (DeadObjectException e) {
@@ -3050,7 +3050,7 @@
                 }
             }
             if (finishing) {
-                if (r.app != null && !r.app.persistent) {
+                if (r.app != null && !r.app.isPersistent()) {
                     r.app.services.remove(r);
                     if (r.whitelistManager) {
                         updateWhitelistManagerLocked(r.app);
@@ -3140,7 +3140,7 @@
                         && (filterByClasses == null
                             || filterByClasses.contains(service.name.getClassName())));
             if (sameComponent
-                    && (service.app == null || evenPersistent || !service.app.persistent)) {
+                    && (service.app == null || evenPersistent || !service.app.isPersistent())) {
                 if (!doit) {
                     return true;
                 }
@@ -3148,7 +3148,7 @@
                 Slog.i(TAG, "  Force stopping service " + service);
                 if (service.app != null) {
                     service.app.removed = killProcess;
-                    if (!service.app.persistent) {
+                    if (!service.app.isPersistent()) {
                         service.app.services.remove(service);
                         if (service.whitelistManager) {
                             updateWhitelistManagerLocked(service.app);
@@ -3302,7 +3302,7 @@
             synchronized (sr.stats.getBatteryStats()) {
                 sr.stats.stopLaunchedLocked();
             }
-            if (sr.app != app && sr.app != null && !sr.app.persistent) {
+            if (sr.app != app && sr.app != null && !sr.app.isPersistent()) {
                 sr.app.services.remove(sr);
             }
             sr.app = null;
@@ -3347,7 +3347,7 @@
                         continue;
                     }
                     // XXX turned off for now until we have more time to get a better policy.
-                    if (false && proc != null && !proc.persistent && proc.thread != null
+                    if (false && proc != null && !proc.isPersistent() && proc.thread != null
                             && proc.pid != 0 && proc.pid != ActivityManagerService.MY_PID
                             && proc.setProcState >= ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
                         proc.kill("bound to service " + sr.name.flattenToShortString()
@@ -3365,7 +3365,7 @@
 
             // Unless the process is persistent, this process record is going away,
             // so make sure the service is cleaned out of it.
-            if (!app.persistent) {
+            if (!app.isPersistent()) {
                 app.services.removeAt(i);
             }
 
@@ -3475,7 +3475,7 @@
         if (r.app != null && r.app.pid == ActivityManagerService.MY_PID) {
             info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
         }
-        if (r.app != null && r.app.persistent) {
+        if (r.app != null && r.app.isPersistent()) {
             info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 5608f97..9f9fe4c 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -30,28 +30,29 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_PRIVATE;
 import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
+import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER;
+import static com.android.server.am.ActivityDisplayProto.ID;
+import static com.android.server.am.ActivityDisplayProto.STACKS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER;
-import static com.android.server.am.ActivityDisplayProto.STACKS;
-import static com.android.server.am.ActivityDisplayProto.ID;
 
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
-import android.app.ActivityTaskManagerInternal;
 import android.app.WindowConfiguration;
 import android.graphics.Point;
 import android.util.IntArray;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
+
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.ConfigurationContainer;
 import com.android.server.wm.DisplayWindowController;
-
 import com.android.server.wm.WindowContainerListener;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1c61f30..70901d0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22,6 +22,8 @@
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.REMOVE_TASKS;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
@@ -30,10 +32,6 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
-import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
-import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
-import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
-import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.GET_PROVIDERS;
 import static android.content.pm.PackageManager.MATCH_ANY_USER;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
@@ -42,10 +40,8 @@
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 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.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
 import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
@@ -67,7 +63,6 @@
 import static android.os.Process.SCHED_RESET_ON_FORK;
 import static android.os.Process.SE_UID;
 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;
@@ -94,16 +89,12 @@
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 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;
-import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
-import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
 import static android.provider.Settings.Global.HIDE_ERROR_DIALOGS;
 import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
 import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
 import static android.provider.Settings.System.FONT_SCALE;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.INVALID_DISPLAY;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -141,8 +132,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IMMERSIVE;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LRU;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_MU;
@@ -153,18 +142,15 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_URI_PERMISSION;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.am.MemoryStatUtil.hasMemcg;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
@@ -177,14 +163,9 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackInfo;
-import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
-import android.app.ActivityTaskManagerInternal.ScreenObserver;
-import android.app.ActivityTaskManagerInternal.SleepToken;
 import android.app.ActivityManagerProto;
 import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
 import android.app.ActivityThread;
 import android.app.AlertDialog;
 import android.app.AppGlobals;
@@ -217,7 +198,6 @@
 import android.app.WindowConfiguration.ActivityType;
 import android.app.WindowConfiguration.WindowingMode;
 import android.app.backup.IBackupManager;
-import android.app.servertransaction.ConfigurationChangeItem;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
@@ -272,7 +252,6 @@
 import android.os.DropBoxManager;
 import android.os.Environment;
 import android.os.FactoryTest;
-import android.os.FileObserver;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
@@ -280,7 +259,6 @@
 import android.os.IPermissionController;
 import android.os.IProcessInfoService;
 import android.os.IProgressListener;
-import android.os.LocaleList;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
@@ -311,7 +289,6 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
-import android.text.format.Time;
 import android.text.style.SuggestionSpan;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -338,6 +315,9 @@
 import android.view.WindowManager;
 import android.view.autofill.AutofillManagerInternal;
 
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -382,17 +362,17 @@
 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.am.MemoryStatUtil.MemoryStat;
-import com.android.server.am.ActivityManagerServiceProto;
 import com.android.server.am.ActivityManagerServiceDumpActivitiesProto;
 import com.android.server.am.ActivityManagerServiceDumpBroadcastsProto;
 import com.android.server.am.ActivityManagerServiceDumpProcessesProto;
 import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
 import com.android.server.am.ActivityManagerServiceDumpServicesProto;
+import com.android.server.am.ActivityManagerServiceProto;
+import com.android.server.am.ActivityStack.ActivityState;
 import com.android.server.am.GrantUriProto;
 import com.android.server.am.ImportanceTokenProto;
 import com.android.server.am.MemInfoDumpProto;
+import com.android.server.am.MemoryStatUtil.MemoryStat;
 import com.android.server.am.NeededUriGrantsProto;
 import com.android.server.am.ProcessOomProto;
 import com.android.server.am.ProcessToGcProto;
@@ -404,16 +384,10 @@
 import com.android.server.pm.dex.DexManager;
 import com.android.server.utils.PriorityDump;
 import com.android.server.vr.VrManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
 import com.android.server.wm.WindowManagerService;
 
-import dalvik.system.VMRuntime;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -450,6 +424,10 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
+import dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
 public class ActivityManagerService extends IActivityManager.Stub
         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
 
@@ -728,7 +706,22 @@
      * returned by the package manager), and the keys are ApplicationRecord
      * objects.
      */
-    final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
+    final MyProcessMap mProcessNames = new MyProcessMap();
+    final class MyProcessMap extends ProcessMap<ProcessRecord> {
+        @Override
+        public ProcessRecord put(String name, int uid, ProcessRecord value) {
+            final ProcessRecord r = super.put(name, uid, value);
+            mAtmInternal.onProcessAdded(r.getWindowProcessController());
+            return r;
+        }
+
+        @Override
+        public ProcessRecord remove(String name, int uid) {
+            final ProcessRecord r = super.remove(name, uid);
+            mAtmInternal.onProcessRemoved(name, uid);
+            return r;
+        }
+    }
 
     /**
      * Tracking long-term execution of processes to look for abuse and other
@@ -739,7 +732,7 @@
     /**
      * The currently running isolated processes.
      */
-    final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<ProcessRecord>();
+    final SparseArray<ProcessRecord> mIsolatedProcesses = new SparseArray<>();
 
     /**
      * Counter for assigning isolated process uids, to avoid frequently reusing the
@@ -866,23 +859,6 @@
     boolean mFullPssPending = false;
 
     /**
-     * This is the process holding what we currently consider to be
-     * the "home" activity.
-     */
-    ProcessRecord mHomeProcess;
-
-    /**
-     * This is the process holding the activity the user last visited that
-     * is in a different process from the one they are currently in.
-     */
-    ProcessRecord mPreviousProcess;
-
-    /**
-     * The time at which the previous process was last visible.
-     */
-    long mPreviousProcessVisibleTime;
-
-    /**
      * Track all uids that have actively running processes.
      */
     final SparseArray<UidRecord> mActiveUids = new SparseArray<>();
@@ -2048,13 +2024,13 @@
                 }
 
                 ActivityRecord root = (ActivityRecord)msg.obj;
-                ProcessRecord process = root.app;
+                final WindowProcessController process = root.app;
                 if (process == null) {
                     return;
                 }
 
                 try {
-                    Context context = mContext.createPackageContext(process.info.packageName, 0);
+                    Context context = mContext.createPackageContext(process.mInfo.packageName, 0);
                     String text = mContext.getString(R.string.heavy_weight_notification,
                             context.getApplicationInfo().loadLabel(context.getPackageManager()));
                     Notification notification =
@@ -2438,8 +2414,9 @@
 
             synchronized (this) {
                 ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
-                app.persistent = true;
+                app.setPersistent(true);
                 app.pid = MY_PID;
+                app.getWindowProcessController().setPid(MY_PID);
                 app.maxAdj = ProcessList.SYSTEM_ADJ;
                 app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
                 synchronized (mPidsSelfLocked) {
@@ -2475,15 +2452,6 @@
         }
     }
 
-    public void setActivityTaskManager(ActivityTaskManagerService atm) {
-        synchronized (this) {
-            mActivityTaskManager = atm;
-            mActivityTaskManager.setActivityManagerService(this);
-            mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
-            mStackSupervisor = mActivityTaskManager.mStackSupervisor;
-        }
-    }
-
     public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
         mUsageStatsService = usageStatsManager;
     }
@@ -2584,10 +2552,17 @@
 
     public static final class Lifecycle extends SystemService {
         private final ActivityManagerService mService;
+        private static ActivityTaskManagerService sAtm;
 
         public Lifecycle(Context context) {
             super(context);
-            mService = new ActivityManagerService(context);
+            mService = new ActivityManagerService(context, sAtm);
+        }
+
+        public static ActivityManagerService startService(
+                SystemServiceManager ssm, ActivityTaskManagerService atm) {
+            sAtm = atm;
+            return ssm.startService(ActivityManagerService.Lifecycle.class).getService();
         }
 
         @Override
@@ -2744,7 +2719,7 @@
 
     // Note: This method is invoked on the main thread but may need to attach various
     // handlers to other threads.  So take care to be explicit about the looper.
-    public ActivityManagerService(Context systemContext) {
+    public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
         LockGuard.installLock(this, LockGuard.INDEX_ACTIVITY);
         mInjector = new Injector();
         mContext = systemContext;
@@ -2823,6 +2798,11 @@
         mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
         mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
 
+        mActivityTaskManager = atm;
+        mActivityTaskManager.setActivityManagerService(this);
+        mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+        mStackSupervisor = mActivityTaskManager.mStackSupervisor;
+
         mProcessCpuThread = new Thread("CpuTracker") {
             @Override
             public void run() {
@@ -2891,6 +2871,7 @@
         mAppOpsService.publish(mContext);
         Slog.d("AppOps", "AppOpsService published");
         LocalServices.addService(ActivityManagerInternal.class, new LocalService());
+        mActivityTaskManager.onActivityManagerInternalAdded();
         // Wait for the synchronized block started in mProcessCpuThread,
         // so that any other access to mProcessCpuTracker from main thread
         // will be blocked during mProcessCpuTracker initialization.
@@ -3295,7 +3276,7 @@
             String what, Object obj, ProcessRecord srcApp) {
         app.lastActivityTime = now;
 
-        if (app.activities.size() > 0 || app.recentTasks.size() > 0) {
+        if (app.hasActivitiesOrRecentTasks()) {
             // Don't want to touch dependent processes that are hosting activities.
             return index;
         }
@@ -3342,7 +3323,7 @@
         int lrui = mLruProcesses.lastIndexOf(app);
         if (lrui >= 0) {
             if (!app.killed) {
-                if (app.persistent) {
+                if (app.isPersistent()) {
                     Slog.w(TAG, "Removing persistent process that hasn't been killed: " + app);
                 } else {
                     Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);
@@ -3366,8 +3347,8 @@
 
     final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
             ProcessRecord client) {
-        final boolean hasActivity = app.activities.size() > 0 || app.hasClientActivities
-                || app.treatLikeActivity || app.recentTasks.size() > 0;
+        final boolean hasActivity = app.hasActivitiesOrRecentTasks() || app.hasClientActivities
+                || app.treatLikeActivity;
         final boolean hasService = false; // not impl yet. app.services.size() > 0;
         if (!activityChange && hasActivity) {
             // The process has activities, so we are only allowing activity-based adjustments
@@ -3399,7 +3380,7 @@
 
         int lrui = mLruProcesses.lastIndexOf(app);
 
-        if (app.persistent && lrui >= 0) {
+        if (app.isPersistent() && lrui >= 0) {
             // We don't care about the position of persistent processes, as long as
             // they are in the list.
             if (DEBUG_LRU) Slog.d(TAG_LRU, "Not moving, persistent: " + app);
@@ -3471,7 +3452,7 @@
         int nextIndex;
         if (hasActivity) {
             final int N = mLruProcesses.size();
-            if ((app.activities.size() == 0 || app.recentTasks.size() > 0)
+            if ((!app.hasActivities() || app.hasRecentTasks())
                     && mLruProcessActivityStart < (N - 1)) {
                 // Process doesn't have activities, but has clients with
                 // activities...  move it up, but one below the top (the top
@@ -3546,14 +3527,14 @@
             if (cr.binding != null && !cr.serviceDead && cr.binding.service != null
                     && cr.binding.service.app != null
                     && cr.binding.service.app.lruSeq != mLruSeq
-                    && !cr.binding.service.app.persistent) {
+                    && !cr.binding.service.app.isPersistent()) {
                 nextIndex = updateLruProcessInternalLocked(cr.binding.service.app, now, nextIndex,
                         "service connection", cr, app);
             }
         }
         for (int j=app.conProviders.size()-1; j>=0; j--) {
             ContentProviderRecord cpr = app.conProviders.get(j).provider;
-            if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.persistent) {
+            if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.isPersistent()) {
                 nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,
                         "provider reference", cpr, app);
             }
@@ -3583,7 +3564,7 @@
                 && proc.lastCachedPss >= 4000) {
             // Turn this condition on to cause killing to happen regularly, for testing.
             if (proc.baseProcessTracker != null) {
-                proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
+                proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
             }
             proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
         } else if (proc != null && !keepIfLarge
@@ -3592,7 +3573,7 @@
             if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
             if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
                 if (proc.baseProcessTracker != null) {
-                    proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
+                    proc.baseProcessTracker.reportCachedKill(proc.pkgList.mPkgList, proc.lastCachedPss);
                 }
                 proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
             }
@@ -3898,7 +3879,7 @@
             }
 
             if (app.info.isPrivilegedApp() &&
-                    DexManager.isPackageSelectedToRunOob(app.pkgList.keySet())) {
+                    DexManager.isPackageSelectedToRunOob(app.pkgList.mPkgList.keySet())) {
                 runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
             }
 
@@ -3940,7 +3921,7 @@
             }
 
             app.gids = gids;
-            app.requiredAbi = requiredAbi;
+            app.setRequiredAbi(requiredAbi);
             app.instructionSet = instructionSet;
 
             // the per-user SELinux context must be set
@@ -4131,7 +4112,7 @@
             // Ignore
         }
 
-        if (app.persistent) {
+        if (app.isPersistent()) {
             Watchdog.getInstance().processStarted(app.processName, pid);
         }
 
@@ -4190,7 +4171,7 @@
                 "updateUsageStats: comp=" + component + "res=" + resumed);
         final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
-            component.app.uid, component.realActivity.getPackageName(),
+            component.app.mUid, component.realActivity.getPackageName(),
             component.realActivity.getShortClassName(), resumed ?
                         StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__FOREGROUND :
                         StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED__STATE__BACKGROUND);
@@ -4201,7 +4182,7 @@
 
             }
             synchronized (stats) {
-                stats.noteActivityResumedLocked(component.app.uid);
+                stats.noteActivityResumedLocked(component.app.mUid);
             }
         } else {
             if (mUsageStatsService != null) {
@@ -4209,7 +4190,7 @@
                         UsageEvents.Event.MOVE_TO_BACKGROUND);
             }
             synchronized (stats) {
-                stats.noteActivityPausedLocked(component.app.uid);
+                stats.noteActivityPausedLocked(component.app.mUid);
             }
         }
     }
@@ -4678,7 +4659,7 @@
 
         // Inform the activity
         try {
-            activityToCallback.app.thread.scheduleLocalVoiceInteractionStarted(activity,
+            activityToCallback.app.getThread().scheduleLocalVoiceInteractionStarted(activity,
                     voiceInteractor);
             long token = Binder.clearCallingIdentity();
             try {
@@ -4746,14 +4727,7 @@
                 return;
             }
 
-            ArrayList<ActivityRecord> activities = new ArrayList<>(proc.activities);
-            for (int i = 0; i < activities.size(); i++) {
-                ActivityRecord r = activities.get(i);
-                if (!r.finishing && r.isInStackLocked()) {
-                    r.getStack().finishActivityLocked(r, Activity.RESULT_CANCELED,
-                            null, "finish-heavy", true);
-                }
-            }
+            proc.getWindowProcessController().finishActivities();
 
             mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
                     proc.userId, 0));
@@ -4802,11 +4776,10 @@
         }
 
         // Remove this application's activities from active lists.
-        boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
+        boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app.getWindowProcessController());
 
         app.clearRecentTasks();
-
-        app.activities.clear();
+        app.clearActivities();
 
         if (app.instr != null) {
             Slog.w(TAG, "Crash of app " + app.processName
@@ -4879,7 +4852,7 @@
         for (int i=mLruProcesses.size()-1; i>=0; i--) {
             ProcessRecord rec = mLruProcesses.get(i);
             if (rec.thread != null
-                    && rec.setProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+                    && rec.setProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
                 haveBg = true;
                 break;
             }
@@ -5131,7 +5104,7 @@
         return SystemClock.elapsedRealtime() - timeStart;
     }
 
-    private static void dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,
+    public static void dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,
             ArrayList<Integer> nativePids, ArrayList<Integer> extraPids) {
 
         // We don't need any sort of inotify based monitoring when we're dumping traces via
@@ -5207,90 +5180,6 @@
         }
     }
 
-    final void logAppTooSlow(ProcessRecord app, long startTime, String msg) {
-        if (true || Build.IS_USER) {
-            return;
-        }
-
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-        StrictMode.allowThreadDiskWrites();
-        try {
-            File tracesDir = new File("/data/anr");
-            File tracesFile = null;
-            try {
-                tracesFile = File.createTempFile("app_slow", null, tracesDir);
-
-                StringBuilder sb = new StringBuilder();
-                Time tobj = new Time();
-                tobj.set(System.currentTimeMillis());
-                sb.append(tobj.format("%Y-%m-%d %H:%M:%S"));
-                sb.append(": ");
-                TimeUtils.formatDuration(SystemClock.uptimeMillis()-startTime, sb);
-                sb.append(" since ");
-                sb.append(msg);
-                FileOutputStream fos = new FileOutputStream(tracesFile);
-                fos.write(sb.toString().getBytes());
-                if (app == null) {
-                    fos.write("\n*** No application process!".getBytes());
-                }
-                fos.close();
-                FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
-            } catch (IOException e) {
-                Slog.w(TAG, "Unable to prepare slow app traces file: " + tracesFile, e);
-                return;
-            }
-
-            if (app != null && app.pid > 0) {
-                ArrayList<Integer> firstPids = new ArrayList<Integer>();
-                firstPids.add(app.pid);
-                dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, null, null);
-            }
-
-            File lastTracesFile = null;
-            File curTracesFile = null;
-            for (int i=9; i>=0; i--) {
-                String name = String.format(Locale.US, "slow%02d.txt", i);
-                curTracesFile = new File(tracesDir, name);
-                if (curTracesFile.exists()) {
-                    if (lastTracesFile != null) {
-                        curTracesFile.renameTo(lastTracesFile);
-                    } else {
-                        curTracesFile.delete();
-                    }
-                }
-                lastTracesFile = curTracesFile;
-            }
-            tracesFile.renameTo(curTracesFile);
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
-        }
-    }
-
-    @GuardedBy("this")
-    final void showLaunchWarningLocked(final ActivityRecord cur, final ActivityRecord next) {
-        if (!mLaunchWarningShown) {
-            mLaunchWarningShown = true;
-            mUiHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    synchronized (ActivityManagerService.this) {
-                        final Dialog d = new LaunchWarningWindow(mContext, cur, next);
-                        d.show();
-                        mUiHandler.postDelayed(new Runnable() {
-                            @Override
-                            public void run() {
-                                synchronized (ActivityManagerService.this) {
-                                    d.dismiss();
-                                    mLaunchWarningShown = false;
-                                }
-                            }
-                        }, 4000);
-                    }
-                }
-            });
-        }
-    }
-
     @Override
     public boolean clearApplicationUserData(final String packageName, boolean keepState,
             final IPackageDataObserver observer, int userId) {
@@ -5491,7 +5380,7 @@
                     final int NA = apps.size();
                     for (int ia = 0; ia < NA; ia++) {
                         final ProcessRecord app = apps.valueAt(ia);
-                        if (app.persistent) {
+                        if (app.isPersistent()) {
                             // We don't kill persistent processes.
                             continue;
                         }
@@ -5746,7 +5635,7 @@
                         proc.baseProcessTracker.addPss(infos[i].getTotalPss(),
                                 infos[i].getTotalUss(), infos[i].getTotalRss(), false,
                                 ProcessStats.ADD_PSS_EXTERNAL_SLOW, endTime-startTime,
-                                proc.pkgList);
+                                proc.pkgList.mPkgList);
                     }
                 }
             }
@@ -5776,7 +5665,7 @@
                     if (proc.thread != null && proc.setAdj == oomAdj) {
                         // Record this for posterity if the process has been stable.
                         proc.baseProcessTracker.addPss(pss[i], tmpUss[0], tmpUss[2], false,
-                                ProcessStats.ADD_PSS_EXTERNAL, endTime-startTime, proc.pkgList);
+                                ProcessStats.ADD_PSS_EXTERNAL, endTime-startTime, proc.pkgList.mPkgList);
                     }
                 }
             }
@@ -5849,7 +5738,7 @@
             final int NA = apps.size();
             for (int ia=0; ia<NA; ia++) {
                 ProcessRecord app = apps.valueAt(ia);
-                if (app.persistent && !evenPersistent) {
+                if (app.isPersistent() && !evenPersistent) {
                     // we don't kill persistent processes
                     continue;
                 }
@@ -6186,7 +6075,7 @@
         // We shouldn't already have a process under this name, but just in case we
         // need to clean up whatever may be there now.
         ProcessRecord old = removeProcessNameLocked(proc.processName, proc.uid);
-        if (old == proc && proc.persistent) {
+        if (old == proc && proc.isPersistent()) {
             // We are re-adding a persistent process.  Whatevs!  Just leave it there.
             Slog.w(TAG, "Re-adding persistent process " + proc);
         } else if (old != null) {
@@ -6253,7 +6142,7 @@
                 }
             }
             boolean willRestart = false;
-            if (app.persistent && !app.isolated) {
+            if (app.isPersistent() && !app.isolated) {
                 if (!callerWillRestart) {
                     willRestart = true;
                 } else {
@@ -6406,7 +6295,7 @@
 
         app.makeActive(thread, mProcessStats);
         app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
-        app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+        app.setCurrentSchedulingGroup(app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT);
         app.forcingToImportant = null;
         updateProcessForegroundLocked(app, false, false);
         app.hasShownUi = false;
@@ -6585,7 +6474,7 @@
                         app.instr.mWatcher,
                         app.instr.mUiAutomationConnection, testMode,
                         mBinderTransactionTrackingEnabled, enableTrackAllocation,
-                        isRestrictedBackupMode || !normalMode, app.persistent,
+                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                         new Configuration(getGlobalConfiguration()), app.compat,
                         getCommonServicesLocked(app.isolated),
                         mCoreSettingsObserver.getCoreSettingsLocked(),
@@ -6594,7 +6483,7 @@
                 thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                         null, null, null, testMode,
                         mBinderTransactionTrackingEnabled, enableTrackAllocation,
-                        isRestrictedBackupMode || !normalMode, app.persistent,
+                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                         new Configuration(getGlobalConfiguration()), app.compat,
                         getCommonServicesLocked(app.isolated),
                         mCoreSettingsObserver.getCoreSettingsLocked(),
@@ -9457,7 +9346,7 @@
             if (conn.stableCount == 0 && conn.unstableCount == 0) {
                 cpr.connections.remove(conn);
                 conn.client.conProviders.remove(conn);
-                if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
+                if (conn.client.setProcState < PROCESS_STATE_LAST_ACTIVITY) {
                     // The client is more important than last activity -- note the time this
                     // is happening, so we keep the old provider process around a bit as last
                     // activity to avoid thrashing it.
@@ -10457,9 +10346,9 @@
                 && userId == UserHandle.USER_SYSTEM
                 && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
             // The system process is initialized to SCHED_GROUP_DEFAULT in init.rc.
-            r.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+            r.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
             r.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-            r.persistent = true;
+            r.setPersistent(true);
             r.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
         }
         if (isolated && isolatedUid != 0) {
@@ -10558,7 +10447,7 @@
         }
 
         if ((info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
-            app.persistent = true;
+            app.setPersistent(true);
             app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
         }
         if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
@@ -11109,7 +10998,10 @@
 
 
     public static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
-        return r != null ? getInputDispatchingTimeoutLocked(r.app) : KEY_DISPATCHING_TIMEOUT;
+        if (r == null || !r.hasProcess()) {
+            return KEY_DISPATCHING_TIMEOUT;
+        }
+        return getInputDispatchingTimeoutLocked((ProcessRecord) r.app.mOwner);
     }
 
     public static long getInputDispatchingTimeoutLocked(ProcessRecord r) {
@@ -11326,7 +11218,7 @@
                         Slog.d("UI_FIFO", "Set RenderThread tid " + tid + " for pid " + pid);
                     }
                     // promote to FIFO now
-                    if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
+                    if (proc.getCurrentSchedulingGroup() == ProcessList.SCHED_GROUP_TOP_APP) {
                         if (DEBUG_OOM_ADJ) Slog.d("UI_FIFO", "Promoting " + tid + "out of band");
                         if (mUseFifoUiScheduling) {
                             setThreadScheduler(proc.renderThreadTid,
@@ -12294,7 +12186,7 @@
 
         final boolean isFatal = Build.IS_ENG || Settings.Global
                 .getInt(mContext.getContentResolver(), Settings.Global.WTF_IS_FATAL, 0) != 0;
-        final boolean isSystem = (r == null) || r.persistent;
+        final boolean isSystem = (r == null) || r.isPersistent();
 
         if (isFatal && !isSystem) {
             mAppErrors.crashApplication(r, crashInfo);
@@ -12457,8 +12349,8 @@
         if (activity != null) {
             sb.append("Activity: ").append(activity.shortComponentName).append("\n");
         }
-        if (parent != null && parent.app != null && parent.app.pid != process.pid) {
-            sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
+        if (parent != null && parent.app != null && parent.app.getPid() != process.pid) {
+            sb.append("Parent-Process: ").append(parent.app.mName).append("\n");
         }
         if (parent != null && parent != activity) {
             sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
@@ -12560,25 +12452,27 @@
                 if (!allUsers && app.userId != userId) {
                     continue;
                 }
-                if ((app.thread != null) && (app.crashing || app.notResponding)) {
+                final boolean crashing = app.isCrashing();
+                final boolean notResponding = app.isNotResponding();
+                if ((app.thread != null) && (crashing || notResponding)) {
                     // This one's in trouble, so we'll generate a report for it
                     // crashes are higher priority (in case there's a crash *and* an anr)
                     ActivityManager.ProcessErrorStateInfo report = null;
-                    if (app.crashing) {
+                    if (crashing) {
                         report = app.crashingReport;
-                    } else if (app.notResponding) {
+                    } else if (notResponding) {
                         report = app.notRespondingReport;
                     }
 
                     if (report != null) {
                         if (errList == null) {
-                            errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
+                            errList = new ArrayList<>(1);
                         }
                         errList.add(report);
                     } else {
                         Slog.w(TAG, "Missing app error report, app = " + app.processName +
-                                " crashing = " + app.crashing +
-                                " notResponding = " + app.notResponding);
+                                " crashing = " + crashing +
+                                " notResponding = " + notResponding);
                     }
                 }
             }
@@ -12608,10 +12502,10 @@
         if (mHeavyWeightProcess == app) {
             outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
         }
-        if (app.persistent) {
+        if (app.isPersistent()) {
             outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_PERSISTENT;
         }
-        if (app.activities.size() > 0) {
+        if (app.hasActivities()) {
             outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HAS_ACTIVITIES;
         }
         outInfo.lastTrimLevel = app.trimMemoryLevel;
@@ -12645,7 +12539,7 @@
                         || (!allUids && app.uid != callingUid)) {
                     continue;
                 }
-                if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
+                if ((app.thread != null) && (!app.isCrashing() && !app.isNotResponding())) {
                     // Generate process state info for running application
                     ActivityManager.RunningAppProcessInfo currApp =
                         new ActivityManager.RunningAppProcessInfo(app.processName,
@@ -12658,7 +12552,7 @@
                                         app.adjSourceProcState);
                     } else if (app.adjSource instanceof ActivityRecord) {
                         ActivityRecord r = (ActivityRecord)app.adjSource;
-                        if (r.app != null) currApp.importanceReasonPid = r.app.pid;
+                        if (r.app != null) currApp.importanceReasonPid = r.app.getPid();
                     }
                     if (app.adjTarget instanceof ComponentName) {
                         currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
@@ -13461,11 +13355,11 @@
                         pw.println("  All known processes:");
                         needSep = true;
                     }
-                    pw.print(r.persistent ? "  *PERS*" : "  *APP*");
+                    pw.print(r.isPersistent() ? "  *PERS*" : "  *APP*");
                         pw.print(" UID "); pw.print(procs.keyAt(ia));
                         pw.print(" "); pw.println(r);
                     r.dump(pw, "    ");
-                    if (r.persistent) {
+                    if (r.isPersistent()) {
                         numPers++;
                     }
                 }
@@ -13617,27 +13511,27 @@
             needSep = false;
             mUserController.dump(pw, dumpAll);
         }
-        if (mHomeProcess != null && (dumpPackage == null
-                || mHomeProcess.pkgList.containsKey(dumpPackage))) {
+        if (mActivityTaskManager.mHomeProcess != null && (dumpPackage == null
+                || mActivityTaskManager.mHomeProcess.mPkgList.contains(dumpPackage))) {
             if (needSep) {
                 pw.println();
                 needSep = false;
             }
-            pw.println("  mHomeProcess: " + mHomeProcess);
+            pw.println("  mHomeProcess: " + mActivityTaskManager.mHomeProcess);
         }
-        if (mPreviousProcess != null && (dumpPackage == null
-                || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
+        if (mActivityTaskManager.mPreviousProcess != null && (dumpPackage == null
+                || mActivityTaskManager.mPreviousProcess.mPkgList.contains(dumpPackage))) {
             if (needSep) {
                 pw.println();
                 needSep = false;
             }
-            pw.println("  mPreviousProcess: " + mPreviousProcess);
+            pw.println("  mPreviousProcess: " + mActivityTaskManager.mPreviousProcess);
         }
-        if (dumpAll && (mPreviousProcess == null || dumpPackage == null
-                || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
+        if (dumpAll && (mActivityTaskManager.mPreviousProcess == null || dumpPackage == null
+                || mActivityTaskManager.mPreviousProcess.mPkgList.contains(dumpPackage))) {
             StringBuilder sb = new StringBuilder(128);
             sb.append("  mPreviousProcessVisibleTime: ");
-            TimeUtils.formatDuration(mPreviousProcessVisibleTime, sb);
+            TimeUtils.formatDuration(mActivityTaskManager.mPreviousProcessVisibleTime, sb);
             pw.println(sb);
         }
         if (mHeavyWeightProcess != null && (dumpPackage == null
@@ -13933,7 +13827,7 @@
                     continue;
                 }
                 r.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PROCS);
-                if (r.persistent) {
+                if (r.isPersistent()) {
                     numPers++;
                 }
             }
@@ -14043,15 +13937,15 @@
             proto.write(ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE, mActivityTaskManager.getFocusedStack().mConfigWillChange);
         }
 
-        if (mHomeProcess != null && (dumpPackage == null
-                || mHomeProcess.pkgList.containsKey(dumpPackage))) {
-            mHomeProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HOME_PROC);
+        if (mActivityTaskManager.mHomeProcess != null && (dumpPackage == null
+                || mActivityTaskManager.mHomeProcess.mPkgList.contains(dumpPackage))) {
+            ((ProcessRecord) mActivityTaskManager.mHomeProcess.mOwner).writeToProto(proto, ActivityManagerServiceDumpProcessesProto.HOME_PROC);
         }
 
-        if (mPreviousProcess != null && (dumpPackage == null
-                || mPreviousProcess.pkgList.containsKey(dumpPackage))) {
-            mPreviousProcess.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC);
-            proto.write(ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mPreviousProcessVisibleTime);
+        if (mActivityTaskManager.mPreviousProcess != null && (dumpPackage == null
+                || mActivityTaskManager.mPreviousProcess.mPkgList.contains(dumpPackage))) {
+            ((ProcessRecord) mActivityTaskManager.mPreviousProcess.mOwner).writeToProto(proto, ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC);
+            proto.write(ActivityManagerServiceDumpProcessesProto.PREVIOUS_PROC_VISIBLE_TIME_MS, mActivityTaskManager.mPreviousProcessVisibleTime);
         }
 
         if (mHeavyWeightProcess != null && (dumpPackage == null
@@ -14322,8 +14216,8 @@
         dumpProcessesToGc(pw, needSep, null);
 
         pw.println();
-        pw.println("  mHomeProcess: " + mHomeProcess);
-        pw.println("  mPreviousProcess: " + mPreviousProcess);
+        pw.println("  mHomeProcess: " + mActivityTaskManager.mHomeProcess);
+        pw.println("  mPreviousProcess: " + mActivityTaskManager.mPreviousProcess);
         if (mHeavyWeightProcess != null) {
             pw.println("  mHeavyWeightProcess: " + mHeavyWeightProcess);
         }
@@ -14495,20 +14389,20 @@
             pw.print(prefix); pw.print("ACTIVITY "); pw.print(r.shortComponentName);
                     pw.print(" "); pw.print(Integer.toHexString(System.identityHashCode(r)));
                     pw.print(" pid=");
-                    if (r.app != null) pw.println(r.app.pid);
+                    if (r.hasProcess()) pw.println(r.app.getPid());
                     else pw.println("(not running)");
             if (dumpAll) {
                 r.dump(pw, innerPrefix);
             }
         }
-        if (r.app != null && r.app.thread != null) {
+        if (r.attachedToProcess()) {
             // flush anything that is already in the PrintWriter since the thread is going
             // to write to the file descriptor directly
             pw.flush();
             try {
                 TransferPipe tp = new TransferPipe();
                 try {
-                    r.app.thread.dumpActivity(tp.getWriteFd(),
+                    r.app.getThread().dumpActivity(tp.getWriteFd(),
                             r.appToken, innerPrefix, args);
                     tp.go(fd);
                 } finally {
@@ -14863,9 +14757,9 @@
                 continue;
             }
             pw.println(String.format("%s%s #%2d: %s",
-                    prefix, (r.persistent ? persistentLabel : normalLabel),
+                    prefix, (r.isPersistent() ? persistentLabel : normalLabel),
                     i, r.toString()));
-            if (r.persistent) {
+            if (r.isPersistent()) {
                 numPers++;
             }
         }
@@ -14918,7 +14812,7 @@
             ProcessRecord r = list.get(i).first;
             long token = proto.start(fieldId);
             String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
-            proto.write(ProcessOomProto.PERSISTENT, r.persistent);
+            proto.write(ProcessOomProto.PERSISTENT, r.isPersistent());
             proto.write(ProcessOomProto.NUM, (origList.size()-1)-list.get(i).second);
             proto.write(ProcessOomProto.OOM_ADJ, oomAdj);
             int schedGroup = ProcessOomProto.SCHED_GROUP_UNKNOWN;
@@ -14941,7 +14835,7 @@
             }
             if (r.foregroundActivities) {
                 proto.write(ProcessOomProto.ACTIVITIES, true);
-            } else if (r.foregroundServices) {
+            } else if (r.hasForegroundServices()) {
                 proto.write(ProcessOomProto.SERVICES, true);
             }
             proto.write(ProcessOomProto.STATE, ProcessList.makeProcStateProtoEnum(r.curProcState));
@@ -15038,14 +14932,14 @@
             char foreground;
             if (r.foregroundActivities) {
                 foreground = 'A';
-            } else if (r.foregroundServices) {
+            } else if (r.hasForegroundServices()) {
                 foreground = 'S';
             } else {
                 foreground = ' ';
             }
             String procState = ProcessList.makeProcStateString(r.curProcState);
             pw.print(prefix);
-            pw.print(r.persistent ? persistentLabel : normalLabel);
+            pw.print(r.isPersistent() ? persistentLabel : normalLabel);
             pw.print(" #");
             int num = (origList.size()-1)-list.get(i).second;
             if (num < 10) pw.print(' ');
@@ -15660,7 +15554,7 @@
                 thread = r.thread;
                 pid = r.pid;
                 oomAdj = r.getSetAdjWithServices();
-                hasActivities = r.activities.size() > 0;
+                hasActivities = r.hasActivities();
             }
             if (thread != null) {
                 if (!opts.isCheckinRequest && opts.dumpDetails) {
@@ -15727,7 +15621,7 @@
                     if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
                         // Record this for posterity if the process has been stable.
                         r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true,
-                                reportType, endTime-startTime, r.pkgList);
+                                reportType, endTime-startTime, r.pkgList.mPkgList);
                     }
                 }
 
@@ -16163,7 +16057,7 @@
                 thread = r.thread;
                 pid = r.pid;
                 oomAdj = r.getSetAdjWithServices();
-                hasActivities = r.activities.size() > 0;
+                hasActivities = r.hasActivities();
             }
             if (thread == null) {
                 continue;
@@ -16225,7 +16119,7 @@
                 if (r.thread != null && oomAdj == r.getSetAdjWithServices()) {
                     // Record this for posterity if the process has been stable.
                     r.baseProcessTracker.addPss(myTotalPss, myTotalUss, myTotalRss, true,
-                            reportType, endTime-startTime, r.pkgList);
+                            reportType, endTime-startTime, r.pkgList.mPkgList);
                 }
             }
 
@@ -16791,7 +16685,7 @@
             ProcessRecord capp = conn.client;
             conn.dead = true;
             if (conn.stableCount > 0) {
-                if (!capp.persistent && capp.thread != null
+                if (!capp.isPersistent() && capp.thread != null
                         && capp.pid != 0
                         && capp.pid != MY_PID) {
                     capp.kill("depends on provider "
@@ -16853,8 +16747,8 @@
             app.waitDialog = null;
         }
 
-        app.crashing = false;
-        app.notResponding = false;
+        app.setCrashing(false);
+        app.setNotResponding(false);
 
         app.resetPackageList(mProcessStats);
         app.unlinkDeathRecipient();
@@ -16963,7 +16857,7 @@
             return false;
         }
 
-        if (!app.persistent || app.isolated) {
+        if (!app.isPersistent() || app.isolated) {
             if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                     "Removing non-persistent process during cleanup: " + app);
             if (!replacingPid) {
@@ -16987,12 +16881,7 @@
                 TAG_CLEANUP, "Clean-up removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
-        if (app == mHomeProcess) {
-            mHomeProcess = null;
-        }
-        if (app == mPreviousProcess) {
-            mPreviousProcess = null;
-        }
+        mAtmInternal.onCleanUpApplicationRecord(app.getWindowProcessController());
 
         if (restart && !app.isolated) {
             // We have components that still need to be running in the
@@ -18037,7 +17926,7 @@
                 isCallerSystem = true;
                 break;
             default:
-                isCallerSystem = (callerApp != null) && callerApp.persistent;
+                isCallerSystem = (callerApp != null) && callerApp.isPersistent();
                 break;
         }
 
@@ -19279,7 +19168,7 @@
 
         if (app.thread == null) {
             app.adjSeq = mAdjSeq;
-            app.curSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
+            app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_BACKGROUND);
             app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
             app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ;
             app.completedAdjSeq = app.adjSeq;
@@ -19292,7 +19181,7 @@
         app.empty = false;
         app.cached = false;
 
-        final int activitiesSize = app.activities.size();
+        final WindowProcessController wpc = app.getWindowProcessController();
         final int appUid = app.info.uid;
         final int logUid = mCurOomAdjUid;
 
@@ -19308,7 +19197,7 @@
             app.adjSeq = mAdjSeq;
             app.curRawAdj = app.maxAdj;
             app.foregroundActivities = false;
-            app.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+            app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_DEFAULT);
             app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
             // System processes can do UI, and when they do we want to have
             // them trim their memory after the user leaves the UI.  To
@@ -19317,29 +19206,24 @@
             app.systemNoUi = true;
             if (app == TOP_APP) {
                 app.systemNoUi = false;
-                app.curSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+                app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
                 app.adjType = "pers-top-activity";
             } else if (app.hasTopUi) {
                 // sched group/proc state adjustment is below
                 app.systemNoUi = false;
                 app.adjType = "pers-top-ui";
-            } else if (activitiesSize > 0) {
-                for (int j = 0; j < activitiesSize; j++) {
-                    final ActivityRecord r = app.activities.get(j);
-                    if (r.visible) {
-                        app.systemNoUi = false;
-                    }
-                }
+            } else if (wpc.hasVisibleActivities()) {
+                app.systemNoUi = false;
             }
             if (!app.systemNoUi) {
               if (mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE) {
                   // screen on, promote UI
                   app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT_UI;
-                  app.curSchedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+                  app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_TOP_APP);
               } else {
                   // screen off, restrict UI scheduling
                   app.curProcState = ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
-                  app.curSchedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
+                  app.setCurrentSchedulingGroup(ProcessList.SCHED_GROUP_RESTRICTED);
               }
             }
             app.curAdj = app.maxAdj;
@@ -19438,120 +19322,127 @@
         }
 
         // Examine all activities if not already foreground.
-        if (!foregroundActivities && activitiesSize > 0) {
-            int minLayer = ProcessList.VISIBLE_APP_LAYER_MAX;
-            for (int j = 0; j < activitiesSize; j++) {
-                final ActivityRecord r = app.activities.get(j);
-                if (r.app != app) {
-                    Log.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
-                            + " instead of expected " + app);
-                    if (r.app == null || (r.app.uid == app.uid)) {
-                        // Only fix things up when they look sane
-                        r.setProcess(app);
-                    } else {
-                        continue;
-                    }
-                }
-                if (r.visible) {
-                    // App has a visible activity; only upgrade adjustment.
-                    if (adj > ProcessList.VISIBLE_APP_ADJ) {
-                        adj = ProcessList.VISIBLE_APP_ADJ;
-                        app.adjType = "vis-activity";
-                        if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                            reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                    "Raise adj to vis-activity: " + app);
+        if (!foregroundActivities && wpc.hasActivities()) {
+            final int[] adjHolder = new int[1];
+            adjHolder[0] = adj;
+            final boolean[] foregroundActivitiesHolder = new boolean[1];
+            foregroundActivitiesHolder[0] = foregroundActivities;
+            int[] procStateHolder = new int[1];
+            procStateHolder[0] = procState;
+            int[] schedGroupHolder = new int[1];
+            schedGroupHolder[0] = schedGroup;
+
+            int minLayer = wpc.computeOomAdjFromActivities(ProcessList.VISIBLE_APP_LAYER_MAX,
+                    new WindowProcessController.ComputeOomAdjCallback() {
+                        @Override
+                        public void onVisibleActivity() {
+                            // App has a visible activity; only upgrade adjustment.
+                            if (adjHolder[0] > ProcessList.VISIBLE_APP_ADJ) {
+                                adjHolder[0] = ProcessList.VISIBLE_APP_ADJ;
+                                app.adjType = "vis-activity";
+                                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                            "Raise adj to vis-activity: " + app);
+                                }
+                            }
+                            if (procStateHolder[0] > PROCESS_STATE_CUR_TOP) {
+                                procStateHolder[0] = PROCESS_STATE_CUR_TOP;
+                                app.adjType = "vis-activity";
+                                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                            "Raise procstate to vis-activity (top): " + app);
+                                }
+                            }
+                            if (schedGroupHolder[0] < ProcessList.SCHED_GROUP_DEFAULT) {
+                                schedGroupHolder[0] = ProcessList.SCHED_GROUP_DEFAULT;
+                            }
+                            app.cached = false;
+                            app.empty = false;
+                            foregroundActivitiesHolder[0] = true;
                         }
-                    }
-                    if (procState > PROCESS_STATE_CUR_TOP) {
-                        procState = PROCESS_STATE_CUR_TOP;
-                        app.adjType = "vis-activity";
-                        if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                            reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                    "Raise procstate to vis-activity (top): " + app);
+
+                        @Override
+                        public void onPausedActivity() {
+                            if (adjHolder[0] > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                                adjHolder[0] = ProcessList.PERCEPTIBLE_APP_ADJ;
+                                app.adjType = "pause-activity";
+                                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                            "Raise adj to pause-activity: "  + app);
+                                }
+                            }
+                            if (procStateHolder[0] > PROCESS_STATE_CUR_TOP) {
+                                procStateHolder[0] = PROCESS_STATE_CUR_TOP;
+                                app.adjType = "pause-activity";
+                                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                            "Raise procstate to pause-activity (top): "  + app);
+                                }
+                            }
+                            if (schedGroupHolder[0] < ProcessList.SCHED_GROUP_DEFAULT) {
+                                schedGroupHolder[0] = ProcessList.SCHED_GROUP_DEFAULT;
+                            }
+                            app.cached = false;
+                            app.empty = false;
+                            foregroundActivitiesHolder[0] = true;
                         }
-                    }
-                    if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
-                        schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-                    }
-                    app.cached = false;
-                    app.empty = false;
-                    foregroundActivities = true;
-                    final TaskRecord task = r.getTask();
-                    if (task != null && minLayer > 0) {
-                        final int layer = task.mLayerRank;
-                        if (layer >= 0 && minLayer > layer) {
-                            minLayer = layer;
+
+                        @Override
+                        public void onStoppingActivity(boolean finishing) {
+                            if (adjHolder[0] > ProcessList.PERCEPTIBLE_APP_ADJ) {
+                                adjHolder[0] = ProcessList.PERCEPTIBLE_APP_ADJ;
+                                app.adjType = "stop-activity";
+                                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                            "Raise adj to stop-activity: "  + app);
+                                }
+                            }
+                            // For the process state, we will at this point consider the process to
+                            // be cached. It will be cached either as an activity or empty depending
+                            // on whether the activity is finishing. We do this so that we can treat
+                            // the process as cached for purposes of memory trimming (determining
+                            // current memory level, trim command to send to process) since there
+                            // can be an arbitrary number of stopping processes and they should soon
+                            // all go into the cached state.
+                            if (!finishing) {
+                                if (procStateHolder[0] > PROCESS_STATE_LAST_ACTIVITY) {
+                                    procStateHolder[0] = PROCESS_STATE_LAST_ACTIVITY;
+                                    app.adjType = "stop-activity";
+                                    if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                                        reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                                "Raise procstate to stop-activity: " + app);
+                                    }
+                                }
+                            }
+                            app.cached = false;
+                            app.empty = false;
+                            foregroundActivitiesHolder[0] = true;
                         }
-                    }
-                    break;
-                } else if (r.isState(ActivityState.PAUSING, ActivityState.PAUSED)) {
-                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
-                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                        app.adjType = "pause-activity";
-                        if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                            reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                    "Raise adj to pause-activity: "  + app);
-                        }
-                    }
-                    if (procState > PROCESS_STATE_CUR_TOP) {
-                        procState = PROCESS_STATE_CUR_TOP;
-                        app.adjType = "pause-activity";
-                        if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                            reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                    "Raise procstate to pause-activity (top): "  + app);
-                        }
-                    }
-                    if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
-                        schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-                    }
-                    app.cached = false;
-                    app.empty = false;
-                    foregroundActivities = true;
-                } else if (r.isState(ActivityState.STOPPING)) {
-                    if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
-                        adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                        app.adjType = "stop-activity";
-                        if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                            reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                    "Raise adj to stop-activity: "  + app);
-                        }
-                    }
-                    // For the process state, we will at this point consider the
-                    // process to be cached.  It will be cached either as an activity
-                    // or empty depending on whether the activity is finishing.  We do
-                    // this so that we can treat the process as cached for purposes of
-                    // memory trimming (determing current memory level, trim command to
-                    // send to process) since there can be an arbitrary number of stopping
-                    // processes and they should soon all go into the cached state.
-                    if (!r.finishing) {
-                        if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
-                            procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
-                            app.adjType = "stop-activity";
-                            if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                                reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                        "Raise procstate to stop-activity: " + app);
+
+                        @Override
+                        public void onOtherActivity() {
+                            if (procStateHolder[0] > PROCESS_STATE_CACHED_ACTIVITY) {
+                                procStateHolder[0] = PROCESS_STATE_CACHED_ACTIVITY;
+                                app.adjType = "cch-act";
+                                if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+                                    reportOomAdjMessageLocked(TAG_OOM_ADJ,
+                                            "Raise procstate to cached activity: " + app);
+                                }
                             }
                         }
-                    }
-                    app.cached = false;
-                    app.empty = false;
-                    foregroundActivities = true;
-                } else {
-                    if (procState > ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
-                        procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
-                        app.adjType = "cch-act";
-                        if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
-                            reportOomAdjMessageLocked(TAG_OOM_ADJ,
-                                    "Raise procstate to cached activity: " + app);
-                        }
-                    }
-                }
-            }
+                    });
+
+            adj = adjHolder[0];
+            foregroundActivities = foregroundActivitiesHolder[0];
+            procState = procStateHolder[0];
+            schedGroup = schedGroupHolder[0];
+
             if (adj == ProcessList.VISIBLE_APP_ADJ) {
                 adj += minLayer;
             }
         }
-        if (procState > ActivityManager.PROCESS_STATE_CACHED_RECENT && app.recentTasks.size() > 0) {
+
+        if (procState > ActivityManager.PROCESS_STATE_CACHED_RECENT && app.hasRecentTasks()) {
             procState = ActivityManager.PROCESS_STATE_CACHED_RECENT;
             app.adjType = "cch-rec";
             if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
@@ -19561,7 +19452,7 @@
 
         if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
                 || procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
-            if (app.foregroundServices) {
+            if (app.hasForegroundServices()) {
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                 procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
@@ -19622,7 +19513,7 @@
             }
         }
 
-        if (app == mHomeProcess) {
+        if (wpc == mActivityTaskManager.mHomeProcess) {
             if (adj > ProcessList.HOME_APP_ADJ) {
                 // This process is hosting what we currently consider to be the
                 // home app, so we don't want to let it go into the background.
@@ -19643,7 +19534,7 @@
             }
         }
 
-        if (app == mPreviousProcess && app.activities.size() > 0) {
+        if (wpc == mActivityTaskManager.mPreviousProcess && app.hasActivities()) {
             if (adj > ProcessList.PREVIOUS_APP_ADJ) {
                 // This was the previous process that showed UI to the user.
                 // We want to try to keep it around more aggressively, to give
@@ -19656,8 +19547,8 @@
                     reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise adj to prev: " + app);
                 }
             }
-            if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
-                procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+            if (procState > PROCESS_STATE_LAST_ACTIVITY) {
+                procState = PROCESS_STATE_LAST_ACTIVITY;
                 app.adjType = "previous";
                 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                     reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise procstate to prev: " + app);
@@ -19720,7 +19611,7 @@
                                 "Raise procstate to started service: " + app);
                     }
                 }
-                if (app.hasShownUi && app != mHomeProcess) {
+                if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess) {
                     // If this process has shown some UI, let it immediately
                     // go to the LRU list because it may be pretty heavy with
                     // UI stuff.  We'll tag it with a label just to help
@@ -19783,7 +19674,7 @@
                         }
                         int clientAdj = client.curRawAdj;
                         int clientProcState = client.curProcState;
-                        if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+                        if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
                             // If the other app is cached for any reason, for purposes here
                             // we are going to consider it empty.  The specific cached state
                             // doesn't propagate except under certain conditions.
@@ -19793,7 +19684,7 @@
                         if ((cr.flags&Context.BIND_ALLOW_OOM_MANAGEMENT) != 0) {
                             // Not doing bind OOM management, so treat
                             // this guy more like a started service.
-                            if (app.hasShownUi && app != mHomeProcess) {
+                            if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess) {
                                 // If this process has shown some UI, let it immediately
                                 // go to the LRU list because it may be pretty heavy with
                                 // UI stuff.  We'll tag it with a label just to help
@@ -19826,7 +19717,7 @@
                             // about letting this process get into the LRU
                             // list to be killed and restarted if needed for
                             // memory.
-                            if (app.hasShownUi && app != mHomeProcess
+                            if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess
                                     && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                                 if (adj >= ProcessList.CACHED_APP_MIN_ADJ) {
                                     adjType = "cch-bound-ui-services";
@@ -19870,9 +19761,10 @@
                             // This will treat important bound services identically to
                             // the top app, which may behave differently than generic
                             // foreground work.
-                            if (client.curSchedGroup > schedGroup) {
+                            final int curSchedGroup = client.getCurrentSchedulingGroup();
+                            if (curSchedGroup > schedGroup) {
                                 if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
-                                    schedGroup = client.curSchedGroup;
+                                    schedGroup = curSchedGroup;
                                 } else {
                                     schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                                 }
@@ -20010,14 +19902,14 @@
                 }
                 int clientAdj = client.curRawAdj;
                 int clientProcState = client.curProcState;
-                if (clientProcState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY) {
+                if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
                     // If the other app is cached for any reason, for purposes here
                     // we are going to consider it empty.
                     clientProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
                 }
                 String adjType = null;
                 if (adj > clientAdj) {
-                    if (app.hasShownUi && app != mHomeProcess
+                    if (app.hasShownUi && wpc != mActivityTaskManager.mHomeProcess
                             && clientAdj > ProcessList.PERCEPTIBLE_APP_ADJ) {
                         adjType = "cch-ui-provider";
                     } else {
@@ -20058,7 +19950,7 @@
                 if (procState > clientProcState) {
                     procState = clientProcState;
                 }
-                if (client.curSchedGroup > schedGroup) {
+                if (client.getCurrentSchedulingGroup() > schedGroup) {
                     schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                 }
                 if (adjType != null) {
@@ -20111,8 +20003,8 @@
                             "Raise adj to recent provider: " + app);
                 }
             }
-            if (procState > ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
-                procState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+            if (procState > PROCESS_STATE_LAST_ACTIVITY) {
+                procState = PROCESS_STATE_LAST_ACTIVITY;
                 app.adjType = "recent-provider";
                 if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                     reportOomAdjMessageLocked(TAG_OOM_ADJ,
@@ -20174,7 +20066,7 @@
             } else if (app.treatLikeActivity) {
                 // This is a cached process, but somebody wants us to treat it like it has
                 // an activity, okay!
-                procState = ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+                procState = PROCESS_STATE_CACHED_ACTIVITY;
                 app.adjType = "cch-as-act";
             }
         }
@@ -20233,7 +20125,7 @@
         // worry about this for max adj above, since max adj will always be used to
         // keep it out of the cached vaues.
         app.curAdj = app.modifyRawOomAdj(adj);
-        app.curSchedGroup = schedGroup;
+        app.setCurrentSchedulingGroup(schedGroup);
         app.curProcState = procState;
         app.foregroundActivities = foregroundActivities;
         app.completedAdjSeq = mAdjSeq;
@@ -20250,7 +20142,8 @@
         EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024,
                 swapPss * 1024, rss * 1024, statType, procState, pssDuration);
         proc.lastPssTime = now;
-        proc.baseProcessTracker.addPss(pss, uss, rss, true, statType, pssDuration, proc.pkgList);
+        proc.baseProcessTracker.addPss(
+                pss, uss, rss, true, statType, pssDuration, proc.pkgList.mPkgList);
         if (DEBUG_PSS) Slog.d(TAG_PSS,
                 "pss of " + proc.toShortString() + ": " + pss + " lastPss=" + proc.lastPss
                 + " state=" + ProcessList.makeProcStateString(procState));
@@ -20601,7 +20494,7 @@
                         }
                         app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince
                                 + " dur=" + checkDur + " limit=" + cpuLimit, true);
-                        app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
+                        app.baseProcessTracker.reportExcessiveCpu(app.pkgList.mPkgList);
                     }
                 }
                 app.lastCpuTime = app.curCpuTime;
@@ -20630,12 +20523,13 @@
             app.verifiedAdj = ProcessList.INVALID_ADJ;
         }
 
-        if (app.setSchedGroup != app.curSchedGroup) {
+        final int curSchedGroup = app.getCurrentSchedulingGroup();
+        if (app.setSchedGroup != curSchedGroup) {
             int oldSchedGroup = app.setSchedGroup;
-            app.setSchedGroup = app.curSchedGroup;
+            app.setSchedGroup = curSchedGroup;
             if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mCurOomAdjUid == app.uid) {
                 String msg = "Setting sched group of " + app.processName
-                        + " to " + app.curSchedGroup + ": " + app.adjType;
+                        + " to " + curSchedGroup + ": " + app.adjType;
                 reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
             }
             if (app.waitingToKill != null && app.curReceivers.isEmpty()
@@ -20644,7 +20538,7 @@
                 success = false;
             } else {
                 int processGroup;
-                switch (app.curSchedGroup) {
+                switch (curSchedGroup) {
                     case ProcessList.SCHED_GROUP_BACKGROUND:
                         processGroup = THREAD_GROUP_BG_NONINTERACTIVE;
                         break;
@@ -20662,10 +20556,11 @@
                 long oldId = Binder.clearCallingIdentity();
                 try {
                     setProcessGroup(app.pid, processGroup);
-                    if (app.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
+                    if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
                         // do nothing if we already switched to RT
                         if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
-                            mActivityTaskManager.onTopProcChangedLocked(app);
+                            mActivityTaskManager.onTopProcChangedLocked(
+                                    app.getWindowProcessController());
                             if (mUseFifoUiScheduling) {
                                 // Switch UI pipeline for app to SCHED_FIFO
                                 app.savedPriority = Process.getThreadPriority(app.pid);
@@ -20696,8 +20591,9 @@
                             }
                         }
                     } else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&
-                               app.curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
-                        mActivityTaskManager.onTopProcChangedLocked(app);
+                            curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {
+                        mActivityTaskManager.onTopProcChangedLocked(
+                                app.getWindowProcessController());
                         if (mUseFifoUiScheduling) {
                             try {
                                 // Reset UI pipeline to SCHED_OTHER
@@ -20726,7 +20622,7 @@
                 } catch (Exception e) {
                     if (false) {
                         Slog.w(TAG, "Failed setting process group of " + app.pid
-                                + " to " + app.curSchedGroup);
+                                + " to " + app.getCurrentSchedulingGroup());
                         Slog.w(TAG, "at location", e);
                     }
                 } finally {
@@ -20738,16 +20634,16 @@
             app.repForegroundActivities = app.foregroundActivities;
             changes |= ProcessChangeItem.CHANGE_ACTIVITIES;
         }
-        if (app.repProcState != app.curProcState) {
-            app.repProcState = app.curProcState;
+        if (app.getReportedProcState() != app.curProcState) {
+            app.setReportedProcState(app.curProcState);
             if (app.thread != null) {
                 try {
                     if (false) {
                         //RuntimeException h = new RuntimeException("here");
-                        Slog.i(TAG, "Sending new process state " + app.repProcState
+                        Slog.i(TAG, "Sending new process state " + app.getReportedProcState()
                                 + " to " + app /*, h*/);
                     }
-                    app.thread.setProcessState(app.repProcState);
+                    app.thread.setProcessState(app.getReportedProcState());
                 } catch (RemoteException e) {
                 }
             }
@@ -21034,10 +20930,9 @@
     }
 
     private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
-        if (proc.thread != null) {
-            if (proc.baseProcessTracker != null) {
-                proc.baseProcessTracker.setState(proc.repProcState, memFactor, now, proc.pkgList);
-            }
+        if (proc.thread != null && proc.baseProcessTracker != null) {
+            proc.baseProcessTracker.setState(
+                    proc.getReportedProcState(), memFactor, now, proc.pkgList.mPkgList);
         }
     }
 
@@ -21055,8 +20950,8 @@
     @GuardedBy("this")
     final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
             boolean oomAdj) {
-        if (isForeground != proc.foregroundServices) {
-            proc.foregroundServices = isForeground;
+        if (isForeground != proc.hasForegroundServices()) {
+            proc.setHasForegroundServices(isForeground);
             ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
                     proc.info.uid);
             if (isForeground) {
@@ -21126,7 +21021,8 @@
     @GuardedBy("this")
     final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
         final ActivityRecord TOP_ACT = resumedAppLocked();
-        final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
+        final ProcessRecord TOP_APP = TOP_ACT != null && TOP_ACT.hasProcess()
+                ? (ProcessRecord) TOP_ACT.app.mOwner : null;
         final boolean wasCached = app.cached;
 
         mAdjSeq++;
@@ -21151,7 +21047,8 @@
     @GuardedBy("this")
     final void updateOomAdjLocked() {
         final ActivityRecord TOP_ACT = resumedAppLocked();
-        final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
+        final ProcessRecord TOP_APP = TOP_ACT != null && TOP_ACT.hasProcess()
+                ? (ProcessRecord) TOP_ACT.app.mOwner : null;
         final long now = SystemClock.uptimeMillis();
         final long nowElapsed = SystemClock.elapsedRealtime();
         final long oldTime = now - ProcessList.MAX_EMPTY_TIME;
@@ -21238,7 +21135,7 @@
                 // to the process, do that now.
                 if (app.curAdj >= ProcessList.UNKNOWN_ADJ) {
                     switch (app.curProcState) {
-                        case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+                        case PROCESS_STATE_CACHED_ACTIVITY:
                         case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
                         case ActivityManager.PROCESS_STATE_CACHED_RECENT:
                             // This process is a cached process holding activities...
@@ -21324,7 +21221,7 @@
 
                 // Count the number of process types.
                 switch (app.curProcState) {
-                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
+                    case PROCESS_STATE_CACHED_ACTIVITY:
                     case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
                         mNumCachedHiddenProcs++;
                         numCached++;
@@ -21367,7 +21264,7 @@
                         if (uidRec.curProcState > app.curProcState) {
                             uidRec.curProcState = app.curProcState;
                         }
-                        if (app.foregroundServices) {
+                        if (app.hasForegroundServices()) {
                             uidRec.foregroundServices = true;
                         }
                     }
@@ -21442,8 +21339,8 @@
             }
             int factor = numTrimming/3;
             int minFactor = 2;
-            if (mHomeProcess != null) minFactor++;
-            if (mPreviousProcess != null) minFactor++;
+            if (mActivityTaskManager.mHomeProcess != null) minFactor++;
+            if (mActivityTaskManager.mPreviousProcess != null) minFactor++;
             if (factor < minFactor) factor = minFactor;
             int curLevel = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
             for (int i=N-1; i>=0; i--) {
@@ -21461,19 +21358,6 @@
                             app.thread.scheduleTrimMemory(curLevel);
                         } catch (RemoteException e) {
                         }
-                        if (false) {
-                            // For now we won't do this; our memory trimming seems
-                            // to be good enough at this point that destroying
-                            // activities causes more harm than good.
-                            if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
-                                    && app != mHomeProcess && app != mPreviousProcess) {
-                                // Need to do this on its own message because the stack may not
-                                // be in a consistent state at this point.
-                                // For these apps we will also finish their activities
-                                // to help them free memory.
-                                mStackSupervisor.scheduleDestroyAllActivities(app, "trim");
-                            }
-                        }
                     }
                     app.trimMemoryLevel = curLevel;
                     step++;
@@ -22024,7 +21908,7 @@
         // has been removed.
         for (int i=mRemovedProcesses.size()-1; i>=0; i--) {
             final ProcessRecord app = mRemovedProcesses.get(i);
-            if (app.activities.size() == 0 && app.recentTasks.size() == 0
+            if (!app.hasActivitiesOrRecentTasks()
                     && app.curReceivers.isEmpty() && app.services.size() == 0) {
                 Slog.i(
                     TAG, "Exiting empty application process "
@@ -22043,7 +21927,7 @@
                 cleanUpApplicationRecordLocked(app, false, true, -1, false /*replacingPid*/);
                 mRemovedProcesses.remove(i);
 
-                if (app.persistent) {
+                if (app.isPersistent()) {
                     addAppLocked(app.info, null, false, null /* ABI override */);
                 }
             }
@@ -22069,7 +21953,7 @@
 
             for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
                 ProcessRecord r = mLruProcesses.get(i);
-                if (r.thread != null && r.persistent) {
+                if (r.thread != null && r.isPersistent()) {
                     sendSignal(r.pid, sig);
                 }
             }
@@ -22574,7 +22458,7 @@
                     final int NA = apps.size();
                     for (int ia = 0; ia < NA; ia++) {
                         final ProcessRecord app = apps.valueAt(ia);
-                        if (app.persistent) {
+                        if (app.isPersistent()) {
                             // We don't kill persistent processes.
                             continue;
                         }
@@ -22847,6 +22731,42 @@
         public void closeSystemDialogs(String reason) {
             ActivityManagerService.this.closeSystemDialogs(reason);
         }
+
+        public void killProcessesForRemovedTask(ArrayList<Object> procsToKill) {
+            synchronized (ActivityManagerService.this) {
+                for (int i = 0; i < procsToKill.size(); i++) {
+                    final WindowProcessController wpc =
+                            (WindowProcessController) procsToKill.get(i);
+                    final ProcessRecord pr = (ProcessRecord) wpc.mOwner;
+                    if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
+                            && pr.curReceivers.isEmpty()) {
+                        pr.kill("remove task", true);
+                    } else {
+                        // We delay killing processes that are not in the background or running a
+                        // receiver.
+                        pr.waitingToKill = "remove task";
+                    }
+                }
+            }
+        }
+
+        @Override
+        public boolean hasRunningActivity(int uid, @Nullable String packageName) {
+            if (packageName == null) return false;
+
+            synchronized (ActivityManagerService.this) {
+                for (int i = 0; i < mLruProcesses.size(); i++) {
+                    final ProcessRecord pr = mLruProcesses.get(i);
+                    if (pr.uid != uid) {
+                        continue;
+                    }
+                    if (pr.getWindowProcessController().hasRunningActivity(packageName)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 1611a38..9b08823 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -2,7 +2,7 @@
 
 import static android.app.ActivityManager.START_SUCCESS;
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
-import static android.app.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -154,7 +154,7 @@
             launchedActivityLaunchToken = info.launchedActivity.info.launchToken;
             launchedActivityAppRecordRequiredAbi = info.launchedActivity.app == null
                     ? null
-                    : info.launchedActivity.app.requiredAbi;
+                    : info.launchedActivity.app.getRequiredAbi();
             reason = info.reason;
             startingWindowDelayMs = info.startingWindowDelayMs;
             bindApplicationDelayMs = info.bindApplicationDelayMs;
@@ -246,25 +246,11 @@
         // of caches might be purged so the time until it produces the first frame is very
         // interesting.
         final boolean processSwitch = processRecord == null
-                || !hasStartedActivity(processRecord, launchedActivity);
+                || !processRecord.getWindowProcessController().hasStartedActivity(launchedActivity);
 
         notifyActivityLaunched(resultCode, launchedActivity, processRunning, processSwitch);
     }
 
-    private boolean hasStartedActivity(ProcessRecord record, ActivityRecord launchedActivity) {
-        final ArrayList<ActivityRecord> activities = record.activities;
-        for (int i = activities.size() - 1; i >= 0; i--) {
-            final ActivityRecord activity = activities.get(i);
-            if (launchedActivity == activity) {
-                continue;
-            }
-            if (!activity.stopped) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /**
      * Notifies the tracker the the activity is actually launching.
      *
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7f3f8f3..d40b9b4 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -288,7 +288,7 @@
     AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity
     HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
     UriPermissionOwner uriPermissions; // current special URI access perms.
-    ProcessRecord app;      // if non-null, hosting application
+    WindowProcessController app;      // if non-null, hosting application
     private ActivityState mState;    // current state we are in
     Bundle  icicle;         // last saved activity state
     PersistableBundle persistentState; // last persistently saved activity state
@@ -622,7 +622,7 @@
     }
 
     private void scheduleActivityMovedToDisplay(int displayId, Configuration config) {
-        if (app == null || app.thread == null) {
+        if (!attachedToProcess()) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.w(TAG,
                     "Can't report activity moved to display - client not running, activityRecord="
                             + this + ", displayId=" + displayId);
@@ -633,7 +633,7 @@
                     "Reporting activity moved to display" + ", activityRecord=" + this
                             + ", displayId=" + displayId + ", config=" + config);
 
-            service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+            service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                     MoveToDisplayItem.obtain(displayId, config));
         } catch (RemoteException e) {
             // If process died, whatever.
@@ -641,7 +641,7 @@
     }
 
     private void scheduleConfigurationChanged(Configuration config) {
-        if (app == null || app.thread == null) {
+        if (attachedToProcess()) {
             if (DEBUG_CONFIGURATION) Slog.w(TAG,
                     "Can't report activity configuration update - client not running"
                             + ", activityRecord=" + this);
@@ -651,7 +651,7 @@
             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: "
                     + config);
 
-            service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+            service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                     ActivityConfigurationChangeItem.obtain(config));
         } catch (RemoteException e) {
             // If process died, whatever.
@@ -659,7 +659,7 @@
     }
 
     void updateMultiWindowMode() {
-        if (task == null || task.getStack() == null || app == null || app.thread == null) {
+        if (task == null || task.getStack() == null || !attachedToProcess()) {
             return;
         }
 
@@ -678,7 +678,7 @@
 
     private void scheduleMultiWindowModeChanged(Configuration overrideConfig) {
         try {
-            service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+            service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                     MultiWindowModeChangeItem.obtain(mLastReportedMultiWindowMode, overrideConfig));
         } catch (Exception e) {
             // If process died, I don't care.
@@ -686,7 +686,7 @@
     }
 
     void updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate) {
-        if (task == null || task.getStack() == null || app == null || app.thread == null) {
+        if (task == null || task.getStack() == null || !attachedToProcess()) {
             return;
         }
 
@@ -705,7 +705,7 @@
 
     private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
         try {
-            service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+            service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                     PipModeChangeItem.obtain(mLastReportedPictureInPictureMode,
                             overrideConfig));
         } catch (Exception e) {
@@ -984,7 +984,7 @@
         }
     }
 
-    void setProcess(ProcessRecord proc) {
+    void setProcess(WindowProcessController proc) {
         app = proc;
         final ActivityRecord root = task != null ? task.getRootActivity() : null;
         if (root == this) {
@@ -992,6 +992,14 @@
         }
     }
 
+    boolean hasProcess() {
+        return app != null;
+    }
+
+    boolean attachedToProcess() {
+        return hasProcess() && app.hasThread();
+    }
+
     AppWindowContainerController getWindowContainerController() {
         return mWindowContainerController;
     }
@@ -1366,7 +1374,7 @@
             clearOptionsLocked();
         }
 
-        if (service.mAm != null) {
+        if (service != null) {
             service.getTaskChangeNotificationController().notifyTaskStackChanged();
         }
     }
@@ -1435,13 +1443,13 @@
         // - It is currently resumed or paused. i.e. it is currently visible to the user and we want
         //   the user to see the visual effects caused by the intent delivery now.
         // - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
-        if ((mState == RESUMED || mState == PAUSED
-                || isTopActivityWhileSleeping) && app != null && app.thread != null) {
+        if ((mState == RESUMED || mState == PAUSED || isTopActivityWhileSleeping)
+                && attachedToProcess()) {
             try {
                 ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
                 ar.add(rintent);
                 service.getLifecycleManager().scheduleTransaction(
-                        app.thread, appToken, NewIntentItem.obtain(ar, mState == PAUSED));
+                        app.getThread(), appToken, NewIntentItem.obtain(ar, mState == PAUSED));
                 unsent = false;
             } catch (RemoteException e) {
                 Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -1744,7 +1752,7 @@
             }
             setVisible(true);
             sleeping = false;
-            app.pendingUiClean = true;
+            app.setPendingUiClean(true);
             if (reportToClient) {
                 makeClientVisible();
             } else {
@@ -1764,13 +1772,13 @@
     void makeClientVisible() {
         mClientVisibilityDeferred = false;
         try {
-            service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+            service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                     WindowVisibilityItem.obtain(true /* showWindow */));
             if (shouldPauseWhenBecomingVisible()) {
                 // An activity must be in the {@link PAUSING} state for the system to validate
                 // the move to {@link PAUSED}.
                 setState(PAUSING, "makeVisibleIfNeeded");
-                service.getLifecycleManager().scheduleTransaction(app.thread, appToken,
+                service.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
                         PauseActivityItem.obtain(finishing, false /* userLeaving */,
                                 configChangeFlags, false /* dontReport */));
             }
@@ -1816,7 +1824,7 @@
         stopFreezingScreenLocked(false);
         try {
             if (returningOptions != null) {
-                app.thread.scheduleOnNewActivityOptions(appToken, returningOptions.toBundle());
+                app.getThread().scheduleOnNewActivityOptions(appToken, returningOptions.toBundle());
             }
         } catch(RemoteException e) {
         }
@@ -1850,9 +1858,9 @@
         stopped = false;
 
         if (isActivityTypeHome()) {
-            ProcessRecord app = task.mActivities.get(0).app;
-            if (app != null && app != service.mAm.mHomeProcess) {
-                service.mAm.mHomeProcess = app;
+            WindowProcessController app = task.mActivities.get(0).app;
+            if (hasProcess() && app != service.mHomeProcess) {
+                service.mHomeProcess = app;
             }
         }
 
@@ -1873,8 +1881,8 @@
         // Mark the point when the activity is resuming
         // TODO: To be more accurate, the mark should be before the onCreate,
         //       not after the onResume. But for subsequent starts, onResume is fine.
-        if (app != null) {
-            cpuTimeAtResume = service.mAm.mProcessCpuTracker.getCpuTimeForPid(app.pid);
+        if (hasProcess()) {
+            cpuTimeAtResume = service.mAm.mProcessCpuTracker.getCpuTimeForPid(app.getPid());
         } else {
             cpuTimeAtResume = 0; // Couldn't get the cpu time of process
         }
@@ -1970,15 +1978,15 @@
 
     // IApplicationToken
 
-    public boolean mayFreezeScreenLocked(ProcessRecord app) {
+    public boolean mayFreezeScreenLocked(WindowProcessController app) {
         // Only freeze the screen if this activity is currently attached to
         // an application, and that application is not blocked or unresponding.
         // In any other case, we can't count on getting the screen unfrozen,
         // so it is best to leave as-is.
-        return app != null && !app.crashing && !app.notResponding;
+        return hasProcess() && !app.isCrashing() && !app.isNotResponding();
     }
 
-    public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
+    public void startFreezingScreenLocked(WindowProcessController app, int configChanges) {
         if (mayFreezeScreenLocked(app)) {
             mWindowContainerController.startFreezingScreen(configChanges);
         }
@@ -2135,17 +2143,17 @@
     @Override
     public boolean keyDispatchingTimedOut(String reason, int windowPid) {
         ActivityRecord anrActivity;
-        ProcessRecord anrApp;
+        WindowProcessController anrApp;
         boolean windowFromSameProcessAsActivity;
         synchronized (service.mGlobalLock) {
             anrActivity = getWaitingHistoryRecordLocked();
             anrApp = app;
             windowFromSameProcessAsActivity =
-                    app == null || app.pid == windowPid || windowPid == -1;
+                    !hasProcess() || app.getPid() == windowPid || windowPid == -1;
         }
         if (windowFromSameProcessAsActivity) {
             return service.mAm.inputDispatchingTimedOut(
-                    anrApp, anrActivity, this, false, reason);
+                    (ProcessRecord) anrApp.mOwner, anrActivity, this, false, reason);
         } else {
             // In this case another process added windows using this activity token. So, we call the
             // generic service input dispatch timed out method so that the right process is blamed.
@@ -2202,9 +2210,9 @@
         if (!force && sleeping == _sleeping) {
             return;
         }
-        if (app != null && app.thread != null) {
+        if (attachedToProcess()) {
             try {
-                app.thread.scheduleSleeping(appToken, _sleeping);
+                app.getThread().scheduleSleeping(appToken, _sleeping);
                 if (_sleeping && !mStackSupervisor.mGoingToSleepActivities.contains(this)) {
                     mStackSupervisor.mGoingToSleepActivities.add(this);
                 }
@@ -2253,7 +2261,7 @@
     }
 
     final boolean isDestroyable() {
-        if (finishing || app == null) {
+        if (finishing || !hasProcess()) {
             // This would be redundant.
             return false;
         }
@@ -2593,7 +2601,7 @@
 
         // If the activity isn't currently running, just leave the new configuration and it will
         // pick that up next time it starts.
-        if (app == null || app.thread == null) {
+        if (!attachedToProcess()) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                     "Configuration doesn't matter not running " + this);
             stopFreezingScreenLocked(false);
@@ -2614,7 +2622,7 @@
             startFreezingScreenLocked(app, globalChanges);
             forceNewConfig = false;
             preserveWindow &= isResizeOnlyChange(changes);
-            if (app == null || app.thread == null) {
+            if (!attachedToProcess()) {
                 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                         "Config is destroying non-running " + this);
                 stack.destroyActivityLocked(this, true, "config");
@@ -2774,7 +2782,7 @@
             } else {
                 lifecycleItem = PauseActivityItem.obtain();
             }
-            final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken);
+            final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), appToken);
             transaction.addCallback(callbackItem);
             transaction.setLifecycleStateRequest(lifecycleItem);
             service.getLifecycleManager().scheduleTransaction(transaction);
@@ -2804,11 +2812,11 @@
     }
 
     private boolean isProcessRunning() {
-        ProcessRecord proc = app;
+        WindowProcessController proc = app;
         if (proc == null) {
-            proc = service.mAm.mProcessNames.get(processName, info.applicationInfo.uid);
+            proc = service.mProcessNames.get(processName, info.applicationInfo.uid);
         }
-        return proc != null && proc.thread != null;
+        return proc != null && proc.hasThread();
     }
 
     /**
@@ -3037,8 +3045,8 @@
         proto.write(STATE, mState.toString());
         proto.write(VISIBLE, visible);
         proto.write(FRONT_OF_TASK, frontOfTask);
-        if (app != null) {
-            proto.write(PROC_ID, app.pid);
+        if (hasProcess()) {
+            proto.write(PROC_ID, app.getPid());
         }
         proto.write(TRANSLUCENT, !fullscreen);
         proto.end(token);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d177702..9b01919 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -367,9 +367,9 @@
     static final int TRANSLUCENT_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
 
     private static class ScheduleDestroyArgs {
-        final ProcessRecord mOwner;
+        final WindowProcessController mOwner;
         final String mReason;
-        ScheduleDestroyArgs(ProcessRecord owner, String reason) {
+        ScheduleDestroyArgs(WindowProcessController owner, String reason) {
             mOwner = owner;
             mReason = reason;
         }
@@ -392,8 +392,8 @@
                     // so we need to be conservative and assume it isn't.
                     Slog.w(TAG, "Activity pause timeout for " + r);
                     synchronized (mService.mGlobalLock) {
-                        if (r.app != null) {
-                            mService.mAm.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
+                        if (r.hasProcess()) {
+                            mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
                         }
                         activityPausedLocked(r.appToken, true);
                     }
@@ -402,7 +402,7 @@
                     ActivityRecord r = (ActivityRecord)msg.obj;
                     synchronized (mService.mGlobalLock) {
                         if (r.continueLaunchTickingLocked()) {
-                            mService.mAm.logAppTooSlow(r.app, r.launchTickTime, "launching " + r);
+                            mService.logAppTooSlow(r.app, r.launchTickTime, "launching " + r);
                         }
                     }
                 } break;
@@ -1453,15 +1453,15 @@
 
         mService.mAm.updateCpuStats();
 
-        if (prev.app != null && prev.app.thread != null) {
+        if (prev.attachedToProcess()) {
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
             try {
                 EventLogTags.writeAmPauseActivity(prev.userId, System.identityHashCode(prev),
                         prev.shortComponentName, "userLeaving=" + userLeaving);
                 mService.mAm.updateUsageStats(prev, false);
 
-                mService.getLifecycleManager().scheduleTransaction(prev.app.thread, prev.appToken,
-                        PauseActivityItem.obtain(prev.finishing, userLeaving,
+                mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
+                        prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
                                 prev.configChangeFlags, pauseImmediately));
             } catch (Exception e) {
                 // Ignore exception, if process died other code will cleanup.
@@ -1563,7 +1563,7 @@
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
                 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
                         "completedPausedLocked");
-            } else if (prev.app != null) {
+            } else if (prev.hasProcess()) {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
                         + " wasStopping=" + wasStopping + " visible=" + prev.visible);
                 if (mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(prev)) {
@@ -1620,9 +1620,9 @@
         if (prev != null) {
             prev.resumeKeyDispatchingLocked();
 
-            if (prev.app != null && prev.cpuTimeAtResume > 0
+            if (prev.hasProcess() && prev.cpuTimeAtResume > 0
                     && mService.mAm.mBatteryStatsService.isOnBattery()) {
-                long diff = mService.mAm.mProcessCpuTracker.getCpuTimeForPid(prev.app.pid)
+                long diff = mService.mAm.mProcessCpuTracker.getCpuTimeForPid(prev.app.getPid())
                         - prev.cpuTimeAtResume;
                 if (diff > 0) {
                     BatteryStatsImpl bsi = mService.mAm.mBatteryStatsService.getActiveStatistics();
@@ -1904,7 +1904,7 @@
                                     true /* ignoreStopState */);
                         }
 
-                        if (r.app == null || r.app.thread == null) {
+                        if (!r.attachedToProcess()) {
                             if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
                                     resumeNextActivity, r)) {
                                 if (activityNdx >= activities.size()) {
@@ -2136,11 +2136,11 @@
             switch (r.getState()) {
                 case STOPPING:
                 case STOPPED:
-                    if (r.app != null && r.app.thread != null) {
+                    if (r.attachedToProcess()) {
                         if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
                                 "Scheduling invisibility: " + r);
-                        mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
-                                WindowVisibilityItem.obtain(false /* showWindow */));
+                        mService.getLifecycleManager().scheduleTransaction(r.app.getThread(),
+                                r.appToken, WindowVisibilityItem.obtain(false /* showWindow */));
                     }
 
                     // Reset the flag indicating that an app can enter picture-in-picture once the
@@ -2217,9 +2217,9 @@
 
             if (waitingActivity != null) {
                 mWindowManager.setWindowOpaque(waitingActivity.appToken, false);
-                if (waitingActivity.app != null && waitingActivity.app.thread != null) {
+                if (waitingActivity.attachedToProcess()) {
                     try {
-                        waitingActivity.app.thread.scheduleTranslucentConversionComplete(
+                        waitingActivity.app.getThread().scheduleTranslucentConversionComplete(
                                 waitingActivity.appToken, r != null);
                     } catch (RemoteException e) {
                     }
@@ -2451,8 +2451,9 @@
             // at the top of the LRU list, since we know we will be needing it
             // very soon and it would be a waste to let it get killed if it
             // happens to be sitting towards the end.
-            if (next.app != null && next.app.thread != null) {
-                mService.mAm.updateLruProcessLocked(next.app, true, null);
+            if (next.attachedToProcess()) {
+                next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
+                        true /* updateLru */, true /* activityChange */, false /* updateOomAdj */);
             }
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             if (lastResumed != null) {
@@ -2577,7 +2578,7 @@
         mStackSupervisor.mNoAnimActivities.clear();
 
         ActivityStack lastStack = mStackSupervisor.getLastStack();
-        if (next.app != null && next.app.thread != null) {
+        if (next.attachedToProcess()) {
             if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next
                     + " stopped=" + next.stopped + " visible=" + next.visible);
 
@@ -2618,9 +2619,9 @@
 
                 next.setState(RESUMED, "resumeTopActivityInnerLocked");
 
-                mService.mAm.updateLruProcessLocked(next.app, true, null);
+                next.app.updateProcessInfo(false /* updateServiceConnectionActivities */,
+                        true /* updateLru */, true /* activityChange */, true /* updateOomAdj */);
                 updateLRUListLocked(next);
-                mService.mAm.updateOomAdjLocked();
 
                 // Have the window manager re-evaluate the orientation of
                 // the screen based on the new activity order.
@@ -2662,8 +2663,8 @@
                 }
 
                 try {
-                    final ClientTransaction transaction = ClientTransaction.obtain(next.app.thread,
-                            next.appToken);
+                    final ClientTransaction transaction =
+                            ClientTransaction.obtain(next.app.getThread(), next.appToken);
                     // Deliver all pending results.
                     ArrayList<ResultInfo> a = next.results;
                     if (a != null) {
@@ -2691,11 +2692,11 @@
                     next.sleeping = false;
                     mService.mAm.getAppWarningsLocked().onResumeActivity(next);
                     mService.mAm.showAskCompatModeDialogLocked(next);
-                    next.app.pendingUiClean = true;
-                    next.app.forceProcessStateUpTo(mService.mAm.mTopProcessState);
+                    next.app.setPendingUiCleanAndForceProcessStateUpTo(
+                            mService.mAm.mTopProcessState);
                     next.clearOptionsLocked();
                     transaction.setLifecycleStateRequest(
-                            ResumeActivityItem.obtain(next.app.repProcState,
+                            ResumeActivityItem.obtain(next.app.getReportedProcState(),
                                     mService.isNextTransitionForward()));
                     mService.getLifecycleManager().scheduleTransaction(transaction);
 
@@ -3345,12 +3346,12 @@
         if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
                 + " : who=" + resultWho + " req=" + requestCode
                 + " res=" + resultCode + " data=" + data);
-        if (mResumedActivity == r && r.app != null && r.app.thread != null) {
+        if (mResumedActivity == r && r.attachedToProcess()) {
             try {
                 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
                 list.add(new ResultInfo(resultWho, requestCode,
                         resultCode, data));
-                mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
+                mService.getLifecycleManager().scheduleTransaction(r.app.getThread(), r.appToken,
                         ActivityResultItem.obtain(list));
                 return;
             } catch (Exception e) {
@@ -3464,7 +3465,7 @@
             }
         }
 
-        if (r.app != null && r.app.thread != null) {
+        if (r.attachedToProcess()) {
             adjustFocusedActivityStack(r, "stopActivity");
             r.resumeKeyDispatchingLocked();
             try {
@@ -3479,7 +3480,7 @@
                 }
                 EventLogTags.writeAmStopActivity(
                         r.userId, System.identityHashCode(r), r.shortComponentName);
-                mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
+                mService.getLifecycleManager().scheduleTransaction(r.app.getThread(), r.appToken,
                         StopActivityItem.obtain(r.visible, r.configChangeFlags));
                 if (shouldSleepOrShutDownActivities()) {
                     r.setSleeping(true);
@@ -3546,7 +3547,7 @@
      * @return The task that was finished in this stack, {@code null} if top running activity does
      *         not belong to the crashed app.
      */
-    final TaskRecord finishTopCrashedActivityLocked(ProcessRecord app, String reason) {
+    final TaskRecord finishTopCrashedActivityLocked(WindowProcessController app, String reason) {
         ActivityRecord r = topRunningActivityLocked();
         TaskRecord finishedTask = null;
         if (r == null || r.app != app) {
@@ -3578,7 +3579,7 @@
         if (activityNdx >= 0) {
             r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);
             if (r.isState(RESUMED, PAUSING, PAUSED)) {
-                if (!r.isActivityTypeHome() || mService.mAm.mHomeProcess != r.app) {
+                if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {
                     Slog.w(TAG, "  Force finishing activity "
                             + r.intent.getComponent().flattenToShortString());
                     finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
@@ -3606,13 +3607,12 @@
                 // Check if any of the activities are using voice
                 for (int activityNdx = tr.mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
                     ActivityRecord r = tr.mActivities.get(activityNdx);
-                    if (r.voiceSession != null
-                            && r.voiceSession.asBinder() == sessionBinder) {
+                    if (r.voiceSession != null && r.voiceSession.asBinder() == sessionBinder) {
                         // Inform of cancellation
                         r.clearVoiceSessionLocked();
                         try {
-                            r.app.thread.scheduleLocalVoiceInteractionStarted((IBinder) r.appToken,
-                                    null);
+                            r.app.getThread().scheduleLocalVoiceInteractionStarted(
+                                    r.appToken, null);
                         } catch (RemoteException re) {
                             // Ok
                         }
@@ -4002,7 +4002,7 @@
                     // TODO(b/64750076): Check if calling pid should really be -1.
                     final int res = mService.getActivityStartController()
                             .obtainStarter(destIntent, "navigateUpTo")
-                            .setCaller(srec.app.thread)
+                            .setCaller(srec.app.getThread())
                             .setActivityInfo(aInfo)
                             .setResultTo(parent.appToken)
                             .setCallingPid(-1)
@@ -4169,13 +4169,13 @@
         }
     }
 
-    final void scheduleDestroyActivities(ProcessRecord owner, String reason) {
+    final void scheduleDestroyActivities(WindowProcessController owner, String reason) {
         Message msg = mHandler.obtainMessage(DESTROY_ACTIVITIES_MSG);
         msg.obj = new ScheduleDestroyArgs(owner, reason);
         mHandler.sendMessage(msg);
     }
 
-    private void destroyActivitiesLocked(ProcessRecord owner, String reason) {
+    private void destroyActivitiesLocked(WindowProcessController owner, String reason) {
         boolean lastIsOpaque = false;
         boolean activityRemoved = false;
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -4220,7 +4220,7 @@
         return false;
     }
 
-    final int releaseSomeActivitiesLocked(ProcessRecord app, ArraySet<TaskRecord> tasks,
+    final int releaseSomeActivitiesLocked(WindowProcessController app, ArraySet<TaskRecord> tasks,
             String reason) {
         // Iterate over tasks starting at the back (oldest) first.
         if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + app);
@@ -4274,7 +4274,7 @@
     final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
         if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(TAG_SWITCH,
                 "Removing activity from " + reason + ": token=" + r
-                        + ", app=" + (r.app != null ? r.app.processName : "(null)"));
+                        + ", app=" + (r.hasProcess() ? r.app.mName : "(null)"));
 
         if (r.isState(DESTROYING, DESTROYED)) {
             if (DEBUG_STATES) Slog.v(TAG_STATES, "activity " + r + " already destroying."
@@ -4290,23 +4290,23 @@
 
         cleanUpActivityLocked(r, false, false);
 
-        final boolean hadApp = r.app != null;
+        final boolean hadApp = r.hasProcess();
 
         if (hadApp) {
             if (removeFromApp) {
-                r.app.activities.remove(r);
-                if (mService.mAm.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
+                r.app.removeActivity(r);
+                if (mService.mAm.mHeavyWeightProcess != null
+                        && mService.mAm.mHeavyWeightProcess.getWindowProcessController() == r.app
+                        && !r.app.hasActivities()) {
                     mService.mAm.mHeavyWeightProcess = null;
                     mService.mAm.mHandler.sendEmptyMessage(
                             ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
                 }
-                if (r.app.activities.isEmpty()) {
+                if (!r.app.hasActivities()) {
                     // Update any services we are bound to that might care about whether
                     // their client may have activities.
-                    mService.mAm.mServices.updateServiceConnectionActivitiesLocked(r.app);
                     // No longer have activities, so update LRU list and oom adj.
-                    mService.mAm.updateLruProcessLocked(r.app, false, null);
-                    mService.mAm.updateOomAdjLocked();
+                    r.app.updateProcessInfo(true, true, false, true);
                 }
             }
 
@@ -4314,7 +4314,7 @@
 
             try {
                 if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
-                mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
+                mService.getLifecycleManager().scheduleTransaction(r.app.getThread(), r.appToken,
                         DestroyActivityItem.obtain(r.finishing, r.configChangeFlags));
             } catch (Exception e) {
                 // We can just ignore exceptions here...  if the process
@@ -4405,7 +4405,7 @@
     }
 
     private void removeHistoryRecordsForAppLocked(ArrayList<ActivityRecord> list,
-            ProcessRecord app, String listName) {
+            WindowProcessController app, String listName) {
         int i = list.size();
         if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
             "Removing app " + app + " from list " + listName + " with " + i + " entries");
@@ -4421,7 +4421,7 @@
         }
     }
 
-    private boolean removeHistoryRecordsForAppLocked(ProcessRecord app) {
+    private boolean removeHistoryRecordsForAppLocked(WindowProcessController app) {
         removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities");
         removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
                 "mStoppingActivities");
@@ -4895,7 +4895,7 @@
                         || (packageName == null && r.userId == userId);
                 if ((userId == UserHandle.USER_ALL || r.userId == userId)
                         && (sameComponent || r.getTask() == lastTask)
-                        && (r.app == null || evenPersistent || !r.app.persistent)) {
+                        && (r.app == null || evenPersistent || !r.app.isPersistent())) {
                     if (!doit) {
                         if (r.finishing) {
                             // If this activity is just finishing, then it is not
@@ -4915,8 +4915,8 @@
                     didSomething = true;
                     Slog.i(TAG, "  Force finishing activity " + r);
                     if (sameComponent) {
-                        if (r.app != null) {
-                            r.app.removed = true;
+                        if (r.hasProcess()) {
+                            r.app.setRemoved(true);
                         }
                         r.app = null;
                     }
@@ -4987,7 +4987,7 @@
      * @param app The app of the activity that died.
      * @return result from removeHistoryRecordsForAppLocked.
      */
-    boolean handleAppDiedLocked(ProcessRecord app) {
+    boolean handleAppDiedLocked(WindowProcessController app) {
         if (mPausingActivity != null && mPausingActivity.app == app) {
             if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE,
                     "App died while pausing: " + mPausingActivity);
@@ -5001,7 +5001,7 @@
         return removeHistoryRecordsForAppLocked(app);
     }
 
-    void handleAppCrashLocked(ProcessRecord app) {
+    void handleAppCrashLocked(WindowProcessController app) {
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 10b721e..85dc11a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -109,7 +109,9 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.StackInfo;
-import android.app.ActivityTaskManagerInternal.SleepToken;
+import android.app.ActivityManagerInternal;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
 import android.app.ActivityOptions;
 import android.app.AppOpsManager;
 import android.app.ProfilerInfo;
@@ -580,21 +582,21 @@
         final ActivityRecord sourceRecord;
         final int startFlags;
         final ActivityStack stack;
-        final ProcessRecord callerApp;
+        final WindowProcessController callerApp;
 
         PendingActivityLaunch(ActivityRecord _r, ActivityRecord _sourceRecord,
-                int _startFlags, ActivityStack _stack, ProcessRecord _callerApp) {
+                int _startFlags, ActivityStack _stack, WindowProcessController app) {
             r = _r;
             sourceRecord = _sourceRecord;
             startFlags = _startFlags;
             stack = _stack;
-            callerApp = _callerApp;
+            callerApp = app;
         }
 
         void sendErrorResult(String message) {
             try {
-                if (callerApp.thread != null) {
-                    callerApp.thread.scheduleCrash(message);
+                if (callerApp.hasThread()) {
+                    callerApp.getThread().scheduleCrash(message);
                 }
             } catch (RemoteException e) {
                 Slog.e(TAG, "Exception scheduling crash of failed "
@@ -1399,12 +1401,13 @@
         beginDeferResume();
 
         try {
-            r.startFreezingScreenLocked(app, 0);
+            final WindowProcessController proc = app.getWindowProcessController();
+            r.startFreezingScreenLocked(proc, 0);
 
             // schedule launch ticks to collect information about slow apps.
             r.startLaunchTickingLocked();
 
-            r.setProcess(app);
+            r.setProcess(proc);
 
             if (getKeyguardController().isKeyguardLocked()) {
                 r.notifyUnknownVisibilityLaunched();
@@ -1448,12 +1451,8 @@
 
             if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
 
-            int idx = app.activities.indexOf(r);
-            if (idx < 0) {
-                app.activities.add(r);
-            }
-            mService.mAm.updateLruProcessLocked(app, true, null);
-            mService.mAm.updateOomAdjLocked();
+            proc.addActivityIfNeeded(r);
+            proc.updateProcessInfo(false, true, true, true);
 
             final LockTaskController lockTaskController = mService.getLockTaskController();
             if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
@@ -1483,7 +1482,7 @@
                         System.identityHashCode(r), task.taskId, r.shortComponentName);
                 if (r.isActivityTypeHome()) {
                     // Home process is the root process of the task.
-                    mService.mAm.mHomeProcess = task.mActivities.get(0).app;
+                    mService.mHomeProcess = task.mActivities.get(0).app;
                 }
                 mService.mAm.notifyPackageUse(r.intent.getComponent().getPackageName(),
                         PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY);
@@ -1534,9 +1533,9 @@
                         // and override configs.
                         mergedConfiguration.getGlobalConfiguration(),
                         mergedConfiguration.getOverrideConfiguration(), r.compat,
-                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
-                        r.persistentState, results, newIntents, mService.isNextTransitionForward(),
-                        profilerInfo));
+                        r.launchedFromPackage, task.voiceInteractor, app.getReportedProcState(),
+                        r.icicle, r.persistentState, results, newIntents,
+                        mService.isNextTransitionForward(), profilerInfo));
 
                 // Set desired final state.
                 final ActivityLifecycleItem lifecycleItem;
@@ -1587,7 +1586,7 @@
                 // This is the first time we failed -- restart process and
                 // retry.
                 r.launchFailed = true;
-                app.activities.remove(r);
+                proc.removeActivity(r);
                 throw e;
             }
         } finally {
@@ -1625,7 +1624,7 @@
         // Update any services we are bound to that might care about whether
         // their client may have activities.
         if (r.app != null) {
-            mService.mAm.mServices.updateServiceConnectionActivitiesLocked(r.app);
+            r.app.updateServiceConnectionActivities();
         }
 
         return true;
@@ -2122,7 +2121,7 @@
         return r;
     }
 
-    boolean handleAppDiedLocked(ProcessRecord app) {
+    boolean handleAppDiedLocked(WindowProcessController app) {
         boolean hasVisibleActivities = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
@@ -2185,7 +2184,7 @@
         // First, found out what is currently the foreground app, so that
         // we don't blow away the previous app if this activity is being
         // hosted by the process that is actually still the foreground.
-        ProcessRecord fgApp = null;
+        WindowProcessController fgApp = null;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
             for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
@@ -2204,11 +2203,11 @@
 
         // Now set this one as the previous process, only if that really
         // makes sense to.
-        if (r.app != null && fgApp != null && r.app != fgApp
-                && r.lastVisibleTime > mService.mAm.mPreviousProcessVisibleTime
-                && r.app != mService.mAm.mHomeProcess) {
-            mService.mAm.mPreviousProcess = r.app;
-            mService.mAm.mPreviousProcessVisibleTime = r.lastVisibleTime;
+        if (r.hasProcess() && fgApp != null && r.app != fgApp
+                && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
+                && r.app != mService.mHomeProcess) {
+            mService.mPreviousProcess = r.app;
+            mService.mPreviousProcessVisibleTime = r.lastVisibleTime;
         }
     }
 
@@ -2254,7 +2253,7 @@
      * @param reason Reason to perform this action.
      * @return The task that was finished in this stack, {@code null} if haven't found any.
      */
-    TaskRecord finishTopCrashedActivitiesLocked(ProcessRecord app, String reason) {
+    TaskRecord finishTopCrashedActivitiesLocked(WindowProcessController app, String reason) {
         TaskRecord finishedTask = null;
         ActivityStack focusedStack = getFocusedStack();
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -3104,36 +3103,34 @@
 
         // Determine if the process(es) for this task should be killed.
         final String pkg = component.getPackageName();
-        ArrayList<ProcessRecord> procsToKill = new ArrayList<>();
-        ArrayMap<String, SparseArray<ProcessRecord>> pmap = mService.mAm.mProcessNames.getMap();
+        ArrayList<Object> procsToKill = new ArrayList<>();
+        ArrayMap<String, SparseArray<WindowProcessController>> pmap =
+                mService.mProcessNames.getMap();
         for (int i = 0; i < pmap.size(); i++) {
 
-            SparseArray<ProcessRecord> uids = pmap.valueAt(i);
+            SparseArray<WindowProcessController> uids = pmap.valueAt(i);
             for (int j = 0; j < uids.size(); j++) {
-                ProcessRecord proc = uids.valueAt(j);
-                if (proc.userId != tr.userId) {
+                WindowProcessController proc = uids.valueAt(j);
+                if (proc.mUserId != tr.userId) {
                     // Don't kill process for a different user.
                     continue;
                 }
-                if (proc == mService.mAm.mHomeProcess) {
+                if (proc == mService.mHomeProcess) {
                     // Don't kill the home process along with tasks from the same package.
                     continue;
                 }
-                if (!proc.pkgList.containsKey(pkg)) {
+                if (!proc.mPkgList.contains(pkg)) {
                     // Don't kill process that is not associated with this task.
                     continue;
                 }
 
-                for (int k = 0; k < proc.activities.size(); k++) {
-                    TaskRecord otherTask = proc.activities.get(k).getTask();
-                    if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
-                        // Don't kill process(es) that has an activity in a different task that is
-                        // also in recents.
-                        return;
-                    }
+                if (!proc.shouldKillProcessForRemovedTask(tr)) {
+                    // Don't kill process(es) that has an activity in a different task that is also
+                    // in recents.
+                    return;
                 }
 
-                if (proc.foregroundServices) {
+                if (proc.hasForegroundServices()) {
                     // Don't kill process(es) with foreground service.
                     return;
                 }
@@ -3143,17 +3140,12 @@
             }
         }
 
-        // Kill the running processes.
-        for (int i = 0; i < procsToKill.size(); i++) {
-            ProcessRecord pr = procsToKill.get(i);
-            if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
-                    && pr.curReceivers.isEmpty()) {
-                pr.kill("remove task", true);
-            } else {
-                // We delay killing processes that are not in the background or running a receiver.
-                pr.waitingToKill = "remove task";
-            }
-        }
+        // Kill the running processes. Post on handle since we don't want to hold the service lock
+        // while calling into AM.
+        final Runnable r = PooledLambda.obtainRunnable(
+                ActivityManagerInternal::killProcessesForRemovedTask, mService.mAmInternal,
+                procsToKill);
+        mService.mH.post(r);
     }
 
     /**
@@ -3656,7 +3648,7 @@
         return false;
     }
 
-    void handleAppCrashLocked(ProcessRecord app) {
+    void handleAppCrashLocked(WindowProcessController app) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
             for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
@@ -3758,7 +3750,7 @@
         }
     }
 
-    void scheduleDestroyAllActivities(ProcessRecord app, String reason) {
+    void scheduleDestroyAllActivities(WindowProcessController app, String reason) {
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
             for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
@@ -3768,44 +3760,9 @@
         }
     }
 
-    void releaseSomeActivitiesLocked(ProcessRecord app, String reason) {
-        // Examine all activities currently running in the process.
-        TaskRecord firstTask = null;
+    void releaseSomeActivitiesLocked(WindowProcessController app, String reason) {
         // Tasks is non-null only if two or more tasks are found.
-        ArraySet<TaskRecord> tasks = null;
-        if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + app);
-        for (int i = 0; i < app.activities.size(); i++) {
-            ActivityRecord r = app.activities.get(i);
-            // First, if we find an activity that is in the process of being destroyed,
-            // then we just aren't going to do anything for now; we want things to settle
-            // down before we try to prune more activities.
-            if (r.finishing || r.isState(DESTROYING, DESTROYED)) {
-                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Abort release; already destroying: " + r);
-                return;
-            }
-            // Don't consider any activies that are currently not in a state where they
-            // can be destroyed.
-            if (r.visible || !r.stopped || !r.haveState
-                    || r.isState(RESUMED, PAUSING, PAUSED, STOPPING)) {
-                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
-                continue;
-            }
-
-            final TaskRecord task = r.getTask();
-            if (task != null) {
-                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task
-                        + " from " + r);
-                if (firstTask == null) {
-                    firstTask = task;
-                } else if (firstTask != task) {
-                    if (tasks == null) {
-                        tasks = new ArraySet<>();
-                        tasks.add(firstTask);
-                    }
-                    tasks.add(task);
-                }
-            }
-        }
+        ArraySet<TaskRecord> tasks = app.getReleaseSomeActivitiesTasks();
         if (tasks == null) {
             if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Didn't find two or more tasks to release");
             return;
@@ -4198,16 +4155,16 @@
                     pw.print(innerPrefix); pw.println(r.app);
                 }
             }
-            if (client && r.app != null && r.app.thread != null) {
+            if (client && r.attachedToProcess()) {
                 // flush anything that is already in the PrintWriter since the thread is going
                 // to write to the file descriptor directly
                 pw.flush();
                 try {
                     TransferPipe tp = new TransferPipe();
                     try {
-                        r.app.thread.dumpActivity(tp.getWriteFd(), r.appToken, innerPrefix, args);
-                        // Short timeout, since blocking here can
-                        // deadlock with the application.
+                        r.app.getThread().dumpActivity(
+                                tp.getWriteFd(), r.appToken, innerPrefix, args);
+                        // Short timeout, since blocking here can deadlock with the application.
                         tp.go(fd, 2000);
                     } finally {
                         tp.kill();
@@ -4567,7 +4524,7 @@
 
         for (int i = task.mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = task.mActivities.get(i);
-            if (r.app != null && r.app.thread != null) {
+            if (r.attachedToProcess()) {
                 mMultiWindowModeChangedActivities.add(r);
             }
         }
@@ -4590,7 +4547,7 @@
     void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, Rect targetStackBounds) {
         for (int i = task.mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = task.mActivities.get(i);
-            if (r.app != null && r.app.thread != null) {
+            if (r.attachedToProcess()) {
                 mPipModeChangedActivities.add(r);
                 // If we are scheduling pip change, then remove this activity from multi-window
                 // change list as the processing of pip change will make sure multi-window changed
@@ -4609,7 +4566,7 @@
         mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
         for (int i = task.mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = task.mActivities.get(i);
-            if (r.app != null && r.app.thread != null) {
+            if (r.attachedToProcess()) {
                 r.updatePictureInPictureMode(targetStackBounds, forceUpdate);
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 6f58aea..dac7715 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -720,10 +720,11 @@
         abort |= !mService.mAm.mIntentFirewall.checkStartActivity(intent, callingUid,
                 callingPid, resolvedType, aInfo.applicationInfo);
 
+        final WindowProcessController callerWpc =
+                callerApp != null ? callerApp.getWindowProcessController() : null;
         // Merge the two options bundles, while realCallerOptions takes precedence.
         ActivityOptions checkedOptions = options != null
-                ? options.getOptions(intent, aInfo, callerApp, mSupervisor)
-                : null;
+                ? options.getOptions(intent, aInfo, callerWpc, mSupervisor) : null;
         if (allowPendingRemoteAnimationRegistryLookup) {
             checkedOptions = mService.getActivityStartController()
                     .getPendingRemoteAnimationRegistry()
@@ -847,7 +848,7 @@
             if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
                     realCallingPid, realCallingUid, "Activity start")) {
                 mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
-                        sourceRecord, startFlags, stack, callerApp));
+                        sourceRecord, startFlags, stack, callerWpc));
                 ActivityOptions.abort(checkedOptions);
                 return ActivityManager.START_SWITCHES_CANCELED;
             }
@@ -1057,13 +1058,8 @@
                         }
                         newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
                                 new IntentSender(target));
-                        if (heavy.activities.size() > 0) {
-                            ActivityRecord hist = heavy.activities.get(0);
-                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
-                                    hist.packageName);
-                            newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
-                                    hist.getTask().taskId);
-                        }
+                        heavy.getWindowProcessController().updateIntentForHeavyWeightActivity(
+                                newIntent);
                         newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
                                 aInfo.packageName);
                         newIntent.setFlags(intent.getFlags());
@@ -1364,7 +1360,7 @@
         final boolean dontStart = top != null && mStartActivity.resultTo == null
                 && top.realActivity.equals(mStartActivity.realActivity)
                 && top.userId == mStartActivity.userId
-                && top.app != null && top.app.thread != null
+                && top.attachedToProcess()
                 && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                 || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK));
         if (dontStart) {
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index d554e0f..d47fb44 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -26,10 +26,11 @@
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.Manifest.permission.STOP_APP_SWITCHES;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
+import static com.android.server.am.ActivityManagerService.dumpStackTraces;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_CONTENT;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
 import static android.app.ActivityTaskManager.INVALID_STACK_ID;
 import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
@@ -46,7 +47,6 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS;
 import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
-import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.res.Configuration.UI_MODE_TYPE_TELEVISION;
@@ -56,7 +56,6 @@
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
-import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS;
 import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
@@ -114,7 +113,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
-import android.app.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
 import android.app.AppGlobals;
 import android.app.IActivityController;
 import android.app.IActivityTaskManager;
@@ -150,7 +149,9 @@
 import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.LocaleList;
@@ -159,6 +160,7 @@
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UpdateLock;
@@ -168,6 +170,7 @@
 import android.service.voice.VoiceInteractionManagerInternal;
 import android.telecom.TelecomManager;
 import android.text.TextUtils;
+import android.text.format.Time;
 import android.util.ArrayMap;
 import android.util.EventLog;
 import android.util.Log;
@@ -176,6 +179,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.StatsLog;
+import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 import android.view.IRecentsAnimationRunner;
 import android.view.RemoteAnimationAdapter;
@@ -184,6 +188,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.internal.app.ProcessMap;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.os.logging.MetricsLoggerWrapper;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -199,10 +204,13 @@
 import com.android.server.wm.WindowManagerService;
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * System service for managing activities and their containers (task, stacks, displays,... ).
@@ -228,6 +236,18 @@
     Object mGlobalLock;
     ActivityStackSupervisor mStackSupervisor;
     WindowManagerService mWindowManager;
+    /** All processes currently running that might have a window organized by name. */
+    final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
+    /** This is the process holding what we currently consider to be the "home" activity. */
+    WindowProcessController mHomeProcess;
+    /**
+     * This is the process holding the activity the user last visited that is in a different process
+     * from the one they are currently in.
+     */
+    WindowProcessController mPreviousProcess;
+    /** The time at which the previous process was last visible. */
+    long mPreviousProcessVisibleTime;
+
     /** List of intents that were used to start the most recent tasks. */
     private RecentTasks mRecentTasks;
     /** State of external calls telling us if the device is awake or asleep. */
@@ -443,7 +463,6 @@
     // TODO: Will be converted to WM lock once transition is complete.
     void setActivityManagerService(ActivityManagerService am) {
         mAm = am;
-        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
         mGlobalLock = mAm;
         mH = new H(mAm.mHandlerThread.getLooper());
         mUiHandler = new UiHandler();
@@ -464,6 +483,10 @@
         mKeyguardController = mStackSupervisor.getKeyguardController();
     }
 
+    void onActivityManagerInternalAdded() {
+        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
+    }
+
     protected ActivityStackSupervisor createStackSupervisor() {
         final ActivityStackSupervisor supervisor = new ActivityStackSupervisor(this, mH.getLooper());
         supervisor.initialize();
@@ -621,7 +644,7 @@
                 SafeActivityOptions.abort(options);
                 return false;
             }
-            if (r.app == null || r.app.thread == null) {
+            if (!r.attachedToProcess()) {
                 // The caller is not running...  d'oh!
                 SafeActivityOptions.abort(options);
                 return false;
@@ -701,7 +724,7 @@
             // TODO(b/64750076): Check if calling pid should really be -1.
             final int res = getActivityStartController()
                     .obtainStarter(intent, "startNextMatchingActivity")
-                    .setCaller(r.app.thread)
+                    .setCaller(r.app.getThread())
                     .setResolvedType(r.resolvedType)
                     .setActivityInfo(aInfo)
                     .setResultTo(resultTo != null ? resultTo.appToken : null)
@@ -804,12 +827,12 @@
             if (sourceRecord.app == null) {
                 throw new SecurityException("Called without a process attached to activity");
             }
-            if (UserHandle.getAppId(sourceRecord.app.uid) != SYSTEM_UID) {
+            if (UserHandle.getAppId(sourceRecord.app.mUid) != 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) {
+                if (sourceRecord.app.mUid != sourceRecord.launchedFromUid) {
                     throw new SecurityException(
-                            "Calling activity in uid " + sourceRecord.app.uid
+                            "Calling activity in uid " + sourceRecord.app.mUid
                                     + " must be system uid or original calling uid "
                                     + sourceRecord.launchedFromUid);
                 }
@@ -830,7 +853,7 @@
         }
 
         if (userId == UserHandle.USER_NULL) {
-            userId = UserHandle.getUserId(sourceRecord.app.uid);
+            userId = UserHandle.getUserId(sourceRecord.app.mUid);
         }
 
         // TODO: Switch to user app stacks here.
@@ -1062,20 +1085,25 @@
     @Override
     public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
         final long origId = Binder.clearCallingIdentity();
-        synchronized (mGlobalLock) {
-            ActivityStack stack = ActivityRecord.getStackLocked(token);
-            if (stack != null) {
-                ActivityRecord r =
-                        mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */,
-                                false /* processPausingActivities */, config);
-                if (stopProfiling) {
-                    if ((mAm.mProfileProc == r.app) && mAm.mProfilerInfo != null) {
-                        mAm.clearProfilerLocked();
-                    }
+        try {
+            WindowProcessController proc = null;
+            synchronized (mGlobalLock) {
+                ActivityStack stack = ActivityRecord.getStackLocked(token);
+                if (stack == null) {
+                    return;
+                }
+                final ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token,
+                        false /* fromTimeout */, false /* processPausingActivities */, config);
+                if (r != null) {
+                    proc = r.app;
+                }
+                if (stopProfiling && proc != null) {
+                    proc.clearProfilerIfNeeded();
                 }
             }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
         }
-        Binder.restoreCallingIdentity(origId);
     }
 
     @Override
@@ -2237,9 +2265,9 @@
         mH.post(() -> {
             synchronized (mGlobalLock) {
                 ActivityRecord r = ActivityRecord.forTokenLocked(token);
-                if (r != null && r.app != null && r.app.thread != null) {
+                if (r != null && r.attachedToProcess()) {
                     try {
-                        r.app.thread.scheduleEnterAnimationComplete(r.appToken);
+                        r.app.getThread().scheduleEnterAnimationComplete(r.appToken);
                     } catch (RemoteException e) {
                     }
                 }
@@ -2477,7 +2505,8 @@
         synchronized (mGlobalLock) {
             final long origId = Binder.clearCallingIdentity();
             try {
-                ProcessRecord app = mAm.getRecordForAppLocked(appInt);
+                WindowProcessController app =
+                        mAm.getRecordForAppLocked(appInt).getWindowProcessController();
                 mStackSupervisor.releaseSomeActivitiesLocked(app, "low-mem");
             } finally {
                 Binder.restoreCallingIdentity(origId);
@@ -2777,7 +2806,7 @@
                 Slog.w(TAG, "getAssistContextExtras failed: no top activity");
                 return null;
             }
-            if (activity.app == null || activity.app.thread == null) {
+            if (!activity.attachedToProcess()) {
                 Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity);
                 return null;
             }
@@ -2797,7 +2826,7 @@
                             + " couldn't be found");
                     return null;
                 }
-                if (activity.app == null || activity.app.thread == null) {
+                if (!activity.attachedToProcess()) {
                     Slog.w(TAG, "enqueueAssistContext failed: no process for " + activity);
                     return null;
                 }
@@ -2809,7 +2838,7 @@
                 extras.putAll(args);
             }
             extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
-            extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
+            extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.mUid);
 
             pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
                     userHandle);
@@ -2820,8 +2849,8 @@
                 mViSessionId++;
             }
             try {
-                activity.app.thread.requestAssistContextExtras(activity.appToken, pae, requestType,
-                        mViSessionId, flags);
+                activity.app.getThread().requestAssistContextExtras(activity.appToken, pae,
+                        requestType, mViSessionId, flags);
                 mPendingAssistExtras.add(pae);
                 mUiHandler.postDelayed(pae, timeout);
             } catch (RemoteException e) {
@@ -3800,7 +3829,7 @@
             synchronized (mAm.mPidsSelfLocked) {
                 final int pid = Binder.getCallingPid();
                 final ProcessRecord proc = mAm.mPidsSelfLocked.get(pid);
-                mVrController.setVrThreadLocked(tid, pid, proc);
+                mVrController.setVrThreadLocked(tid, pid, proc.getWindowProcessController());
             }
         }
     }
@@ -3905,7 +3934,7 @@
         mRecentTasks.notifyTaskPersisterLocked(task, flush);
     }
 
-    void onTopProcChangedLocked(ProcessRecord proc) {
+    void onTopProcChangedLocked(WindowProcessController proc) {
         mVrController.onTopProcChangedLocked(proc);
     }
 
@@ -4307,6 +4336,65 @@
         return kept;
     }
 
+    void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
+        if (true || Build.IS_USER) {
+            return;
+        }
+
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        StrictMode.allowThreadDiskWrites();
+        try {
+            File tracesDir = new File("/data/anr");
+            File tracesFile = null;
+            try {
+                tracesFile = File.createTempFile("app_slow", null, tracesDir);
+
+                StringBuilder sb = new StringBuilder();
+                Time tobj = new Time();
+                tobj.set(System.currentTimeMillis());
+                sb.append(tobj.format("%Y-%m-%d %H:%M:%S"));
+                sb.append(": ");
+                TimeUtils.formatDuration(SystemClock.uptimeMillis()-startTime, sb);
+                sb.append(" since ");
+                sb.append(msg);
+                FileOutputStream fos = new FileOutputStream(tracesFile);
+                fos.write(sb.toString().getBytes());
+                if (app == null) {
+                    fos.write("\n*** No application process!".getBytes());
+                }
+                fos.close();
+                FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
+            } catch (IOException e) {
+                Slog.w(TAG, "Unable to prepare slow app traces file: " + tracesFile, e);
+                return;
+            }
+
+            if (app != null && app.getPid() > 0) {
+                ArrayList<Integer> firstPids = new ArrayList<Integer>();
+                firstPids.add(app.getPid());
+                dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, null, null);
+            }
+
+            File lastTracesFile = null;
+            File curTracesFile = null;
+            for (int i=9; i>=0; i--) {
+                String name = String.format(Locale.US, "slow%02d.txt", i);
+                curTracesFile = new File(tracesDir, name);
+                if (curTracesFile.exists()) {
+                    if (lastTracesFile != null) {
+                        curTracesFile.renameTo(lastTracesFile);
+                    } else {
+                        curTracesFile.delete();
+                    }
+                }
+                lastTracesFile = curTracesFile;
+            }
+            tracesFile.renameTo(curTracesFile);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+    }
+
     final class H extends Handler {
         public H(Looper looper) {
             super(looper, null, true);
@@ -4487,26 +4575,6 @@
         }
 
         @Override
-        public boolean hasRunningActivity(int uid, @Nullable String packageName) {
-            if (packageName == null) return false;
-
-            synchronized (mGlobalLock) {
-                for (int i = 0; i < mAm.mLruProcesses.size(); i++) {
-                    final ProcessRecord processRecord = mAm.mLruProcesses.get(i);
-                    if (processRecord.uid == uid) {
-                        for (int j = 0; j < processRecord.activities.size(); j++) {
-                            final ActivityRecord activityRecord = processRecord.activities.get(j);
-                            if (packageName.equals(activityRecord.packageName)) {
-                                return true;
-                            }
-                        }
-                    }
-                }
-            }
-            return false;
-        }
-
-        @Override
         public void registerScreenObserver(ScreenObserver observer) {
             mScreenObservers.add(observer);
         }
@@ -4575,5 +4643,31 @@
                         caller, callingPid, callingUid);
             }
         }
+
+        @Override
+        public void onProcessAdded(WindowProcessController proc) {
+            synchronized (mGlobalLock) {
+                mProcessNames.put(proc.mName, proc.mUid, proc);
+            }
+        }
+
+        @Override
+        public void onProcessRemoved(String name, int uid) {
+            synchronized (mGlobalLock) {
+                mProcessNames.remove(name, uid);
+            }
+        }
+
+        @Override
+        public void onCleanUpApplicationRecord(WindowProcessController proc) {
+            synchronized (mGlobalLock) {
+                if (proc == mHomeProcess) {
+                    mHomeProcess = null;
+                }
+                if (proc == mPreviousProcess) {
+                    mPreviousProcess = null;
+                }
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/am/AppErrorDialog.java b/services/core/java/com/android/server/am/AppErrorDialog.java
index 68c63a2..cde633d 100644
--- a/services/core/java/com/android/server/am/AppErrorDialog.java
+++ b/services/core/java/com/android/server/am/AppErrorDialog.java
@@ -92,7 +92,7 @@
         attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR
                 | WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
         getWindow().setAttributes(attrs);
-        if (mProc.persistent) {
+        if (mProc.isPersistent()) {
             getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
         }
 
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 5719490..7db98b3 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -25,7 +25,6 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
-import android.app.ActivityThread;
 import android.app.AppOpsManager;
 import android.app.ApplicationErrorReport;
 import android.app.Dialog;
@@ -45,7 +44,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
-import android.util.Log;
 import android.util.Slog;
 import android.util.StatsLog;
 import android.util.SparseArray;
@@ -57,7 +55,6 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Set;
 
 import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
@@ -314,9 +311,9 @@
     }
 
     void killAppAtUserRequestLocked(ProcessRecord app, Dialog fromDialog) {
-        app.crashing = false;
+        app.setCrashing(false);
         app.crashingReport = null;
-        app.notResponding = false;
+        app.setNotResponding(false);
         app.notRespondingReport = null;
         if (app.anrDialog == fromDialog) {
             app.anrDialog = null;
@@ -409,7 +406,7 @@
 
         // If a persistent app is stuck in a crash loop, the device isn't very
         // usable, so we want to consider sending out a rescue party.
-        if (r != null && r.persistent) {
+        if (r != null && r.isPersistent()) {
             RescueParty.notePersistentAppCrash(mContext, r.uid);
         }
 
@@ -493,8 +490,8 @@
                 long orig = Binder.clearCallingIdentity();
                 try {
                     // Kill it with fire!
-                    mService.mStackSupervisor.handleAppCrashLocked(r);
-                    if (!r.persistent) {
+                    mService.mStackSupervisor.handleAppCrashLocked(r.getWindowProcessController());
+                    if (!r.isPersistent()) {
                         mService.removeProcessLocked(r, false, false, "crash");
                         mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
                     }
@@ -571,11 +568,11 @@
 
     private boolean makeAppCrashingLocked(ProcessRecord app,
             String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
-        app.crashing = true;
+        app.setCrashing(true);
         app.crashingReport = generateProcessError(app,
                 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
         startAppProblemLocked(app);
-        app.stopFreezingAllLocked();
+        app.getWindowProcessController().stopFreezingActivities();
         return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
                 data);
     }
@@ -643,7 +640,7 @@
             return null;
         }
 
-        if (!r.crashing && !r.notResponding && !r.forceCrashReport) {
+        if (!r.isCrashing() && !r.isNotResponding() && !r.forceCrashReport) {
             return null;
         }
 
@@ -654,10 +651,10 @@
         report.time = timeMillis;
         report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
 
-        if (r.crashing || r.forceCrashReport) {
+        if (r.isCrashing() || r.forceCrashReport) {
             report.type = ApplicationErrorReport.TYPE_CRASH;
             report.crashInfo = crashInfo;
-        } else if (r.notResponding) {
+        } else if (r.isNotResponding()) {
             report.type = ApplicationErrorReport.TYPE_ANR;
             report.anrInfo = new ApplicationErrorReport.AnrInfo();
 
@@ -715,8 +712,8 @@
                     + " has crashed too many times: killing!");
             EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
                     app.userId, app.info.processName, app.uid);
-            mService.mStackSupervisor.handleAppCrashLocked(app);
-            if (!app.persistent) {
+            mService.mStackSupervisor.handleAppCrashLocked(app.getWindowProcessController());
+            if (!app.isPersistent()) {
                 // We don't want to start this process again until the user
                 // explicitly does so...  but for persistent process, we really
                 // need to keep it running.  If a persistent process is actually
@@ -744,7 +741,7 @@
             mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
         } else {
             final TaskRecord affectedTask =
-                    mService.mStackSupervisor.finishTopCrashedActivitiesLocked(app, reason);
+                    mService.mStackSupervisor.finishTopCrashedActivitiesLocked(app.getWindowProcessController(), reason);
             if (data != null) {
                 data.task = affectedTask;
             }
@@ -762,21 +759,11 @@
         // replaced by a third-party app, clear the package preferred activities from packages
         // with a home activity running in the process to prevent a repeatedly crashing app
         // from blocking the user to manually clear the list.
-        final ArrayList<ActivityRecord> activities = app.activities;
-        if (app == mService.mHomeProcess && activities.size() > 0
-                && (mService.mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
-            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = activities.get(activityNdx);
-                if (r.isActivityTypeHome()) {
-                    Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
-                    try {
-                        ActivityThread.getPackageManager()
-                                .clearPackagePreferredActivities(r.packageName);
-                    } catch (RemoteException c) {
-                        // pm is in same process, this will never happen.
-                    }
-                }
-            }
+        final WindowProcessController proc = app.getWindowProcessController();
+        final WindowProcessController homeProc = mService.mActivityTaskManager.mHomeProcess;
+        if (proc == homeProc && proc.hasActivities()
+                && (homeProc.mInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+            proc.clearPackagePreferredForHomeActivities();
         }
 
         if (!app.isolated) {
@@ -917,10 +904,10 @@
             if (mService.mShuttingDown) {
                 Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
                 return;
-            } else if (app.notResponding) {
+            } else if (app.isNotResponding()) {
                 Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
                 return;
-            } else if (app.crashing) {
+            } else if (app.isCrashing()) {
                 Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
                 return;
             } else if (app.killedByAm) {
@@ -933,7 +920,7 @@
 
             // In case we come through here for the same app before completing
             // this one, mark as anring now so we will bail out.
-            app.notResponding = true;
+            app.setNotResponding(true);
 
             // Log the ANR to the event log.
             EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
@@ -946,8 +933,8 @@
             isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);
             if (!isSilentANR) {
                 int parentPid = app.pid;
-                if (parent != null && parent.app != null && parent.app.pid > 0) {
-                    parentPid = parent.app.pid;
+                if (parent != null && parent.app != null && parent.app.getPid() > 0) {
+                    parentPid = parent.app.getPid();
                 }
                 if (parentPid != app.pid) firstPids.add(parentPid);
 
@@ -958,7 +945,7 @@
                     if (r != null && r.thread != null) {
                         int pid = r.pid;
                         if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
-                            if (r.persistent) {
+                            if (r.isPersistent()) {
                                 firstPids.add(pid);
                                 if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
                             } else if (r.treatLikeActivity) {
@@ -1100,12 +1087,12 @@
 
     private void makeAppNotRespondingLocked(ProcessRecord app,
             String activity, String shortMsg, String longMsg) {
-        app.notResponding = true;
+        app.setNotResponding(true);
         app.notRespondingReport = generateProcessError(app,
                 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
                 activity, shortMsg, longMsg, null);
         startAppProblemLocked(app);
-        app.stopFreezingAllLocked();
+        app.getWindowProcessController().stopFreezingActivities();
     }
 
     void handleShowAnrUi(Message msg) {
diff --git a/services/core/java/com/android/server/am/AppNotRespondingDialog.java b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
index 8a88a69..7c983ff 100644
--- a/services/core/java/com/android/server/am/AppNotRespondingDialog.java
+++ b/services/core/java/com/android/server/am/AppNotRespondingDialog.java
@@ -157,7 +157,7 @@
                                     System.currentTimeMillis(), null);
                         }
 
-                        app.notResponding = false;
+                        app.setNotResponding(false);
                         app.notRespondingReport = null;
                         if (app.anrDialog == AppNotRespondingDialog.this) {
                             app.anrDialog = null;
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index 037f245..395b0da 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -17,13 +17,12 @@
 package com.android.server.am;
 
 import static android.app.ActivityManager.ASSIST_CONTEXT_FULL;
-import static android.app.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.OP_NONE;
+import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
 
 import android.app.ActivityTaskManager;
 import android.app.AppOpsManager;
-import android.app.IActivityManager;
 import android.app.IAssistDataReceiver;
 import android.content.Context;
 import android.graphics.Bitmap;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index c9a26cb..a9fd51d 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -304,7 +304,7 @@
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                     mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                     r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
-                    app.repProcState);
+                    app.getReportedProcState());
             if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                     "Process cur broadcast " + r + " DELIVERED for app " + app);
             started = true;
@@ -492,7 +492,7 @@
                 // correctly ordered with other one-way calls.
                 try {
                     app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
-                            data, extras, ordered, sticky, sendingUser, app.repProcState);
+                            data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
                 // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
                 // DeadObjectException when the process isn't actually dead.
                 //} catch (DeadObjectException ex) {
@@ -618,7 +618,7 @@
         }
 
         if (!skip && (filter.receiverList.app == null || filter.receiverList.app.killed
-                || filter.receiverList.app.crashing)) {
+                || filter.receiverList.app.isCrashing())) {
             Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r
                     + " to " + filter.receiverList + ": process gone or crashing");
             skip = true;
@@ -885,7 +885,7 @@
                 synchronized (mService.mPidsSelfLocked) {
                     ProcessRecord proc = mService.mPidsSelfLocked.get(
                             mPendingBroadcast.curApp.pid);
-                    isDead = proc == null || proc.crashing;
+                    isDead = proc == null || proc.isCrashing();
                 }
             } else {
                 final ProcessRecord proc = mService.mProcessNames.get(
@@ -1210,7 +1210,7 @@
                     + " (uid " + r.callingUid + ")");
             skip = true;
         }
-        if (r.curApp != null && r.curApp.crashing) {
+        if (r.curApp != null && r.curApp.isCrashing()) {
             // If the target process is crashing, just skip it.
             Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r
                     + " to " + r.curApp + ": process crashing");
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index fb55a47..657e0eb 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -19,6 +19,13 @@
 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static android.view.WindowManager.TRANSIT_UNSET;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
 import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -27,15 +34,7 @@
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED;
 import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
-import static android.view.WindowManager.TRANSIT_UNSET;
 
-import android.app.ActivityTaskManagerInternal.SleepToken;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.Trace;
@@ -44,6 +43,7 @@
 
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
 import com.android.server.wm.WindowManagerService;
 
 import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java
index 9348023..6e42aee 100644
--- a/services/core/java/com/android/server/am/NativeCrashListener.java
+++ b/services/core/java/com/android/server/am/NativeCrashListener.java
@@ -29,7 +29,6 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.InterruptedIOException;
-import java.net.InetSocketAddress;
 
 /**
  * Set up a Unix domain socket that debuggerd will connect() to in
@@ -226,7 +225,7 @@
                 }
                 if (pr != null) {
                     // Don't attempt crash reporting for persistent apps
-                    if (pr.persistent) {
+                    if (pr.isPersistent()) {
                         if (DEBUG) {
                             Slog.v(TAG, "Skipping report for persistent app " + pr);
                         }
@@ -260,7 +259,7 @@
                     // even though the process will vanish as soon as we let
                     // debuggerd proceed.
                     synchronized (mAm) {
-                        pr.crashing = true;
+                        pr.setCrashing(true);
                         pr.forceCrashReport = true;
                     }
 
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index caf52e3..5a44ab6 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -54,7 +54,7 @@
  * Full information about a particular process that
  * is currently running.
  */
-final class ProcessRecord {
+final class ProcessRecord implements WindowProcessListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ProcessRecord" : TAG_AM;
 
     private final ActivityManagerService mService; // where we came from
@@ -65,7 +65,37 @@
     final int userId;           // user of process.
     final String processName;   // name of the process
     // List of packages running in the process
-    final ArrayMap<String, ProcessStats.ProcessStateHolder> pkgList = new ArrayMap<>();
+    final PackageList pkgList = new PackageList();
+    final class PackageList {
+        final ArrayMap<String, ProcessStats.ProcessStateHolder> mPkgList = new ArrayMap<>();
+
+        ProcessStats.ProcessStateHolder put(String key, ProcessStats.ProcessStateHolder value) {
+            mWindowProcessController.addPackage(key);
+            return mPkgList.put(key, value);
+        }
+
+        void clear() {
+            mPkgList.clear();
+            mWindowProcessController.clearPackageList();
+        }
+
+        int size() {
+            return mPkgList.size();
+        }
+
+        String keyAt(int index) {
+            return mPkgList.keyAt(index);
+        }
+
+        public ProcessStats.ProcessStateHolder valueAt(int index) {
+            return mPkgList.valueAt(index);
+        }
+
+        boolean containsKey(Object key) {
+            return mPkgList.containsKey(key);
+        }
+    }
+
     final ProcessList.ProcStateMemTracker procStateMemTracker
             = new ProcessList.ProcStateMemTracker();
     UidRecord uidRecord;        // overall state of process's uid.
@@ -78,7 +108,7 @@
     int pid;                    // The process of this application; 0 if none
     String procStatFile;        // path to /proc/<pid>/stat
     int[] gids;                 // The gids this process was launched with
-    String requiredAbi;         // The ABI this process was launched with
+    private String mRequiredAbi;// The ABI this process was launched with
     String instructionSet;      // The instruction set this process was launched with
     boolean starting;           // True if the process is being started
     long lastActivityTime;      // For managing the LRU list
@@ -96,12 +126,11 @@
     int curAdj;                 // Current OOM adjustment for this process
     int setAdj;                 // Last set OOM adjustment for this process
     int verifiedAdj;            // The last adjustment that was verified as actually being set
-    int curSchedGroup;          // Currently desired scheduling class
+    private int mCurSchedGroup; // Currently desired scheduling class
     int setSchedGroup;          // Last set to background scheduling class
-    int vrThreadTid;            // Thread currently set for VR scheduling
     int trimMemoryLevel;        // Last selected memory trimming level
     int curProcState = PROCESS_STATE_NONEXISTENT; // Currently computed process state
-    int repProcState = PROCESS_STATE_NONEXISTENT; // Last reported process state
+    private int mRepProcState = 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 pssStatType;            // The type of stat collection that we are currently requesting
@@ -112,7 +141,7 @@
     boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
     boolean hasClientActivities;  // Are there any client services with activities?
     boolean hasStartedServices; // Are there any started services running in this process?
-    boolean foregroundServices; // Running any services that are foreground?
+    private boolean mHasForegroundServices; // Running any services that are foreground?
     boolean foregroundActivities; // Running any activities that are foreground?
     boolean repForegroundActivities; // Last reported foreground activities.
     boolean systemNoUi;         // This is a system process, but not currently showing UI.
@@ -173,10 +202,8 @@
     Object adjTarget;           // Debugging: target component impacting oom_adj.
     Runnable crashHandler;      // Optional local handler to be invoked in the process crash.
 
-    // all activities running in the process
-    final ArrayList<ActivityRecord> activities = new ArrayList<>();
-    // any tasks this process had run root activities in
-    final ArrayList<TaskRecord> recentTasks = new ArrayList<>();
+    // Controller for driving the process state on the window manager side.
+    final private WindowProcessController mWindowProcessController;
     // all ServiceRecord running in this process
     final ArraySet<ServiceRecord> services = new ArraySet<>();
     // services that are currently executing code (need to remain foreground).
@@ -194,11 +221,11 @@
     String[] isolatedEntryPointArgs; // Arguments to pass to isolatedEntryPoint's main().
 
     boolean execServicesFg;     // do we need to be executing services in the foreground?
-    boolean persistent;         // always keep this application running?
-    boolean crashing;           // are we in the process of crashing?
+    private boolean mPersistent;// always keep this application running?
+    private boolean mCrashing;  // are we in the process of crashing?
     Dialog crashDialog;         // dialog being displayed due to crash.
     boolean forceCrashReport;   // suppress normal auto-dismiss of crash dialog & report UI?
-    boolean notResponding;      // does the app have a not responding dialog?
+    private boolean mNotResponding; // does the app have a not responding dialog?
     Dialog anrDialog;           // dialog being displayed due to app not resp.
     boolean removed;            // has app package been removed from device?
     boolean debugging;          // was app launched for debugging?
@@ -259,7 +286,7 @@
             }
         }
         pw.println("}");
-        pw.print(prefix); pw.print("requiredAbi="); pw.print(requiredAbi);
+        pw.print(prefix); pw.print("mRequiredAbi="); pw.print(mRequiredAbi);
                 pw.print(" instructionSet="); pw.println(instructionSet);
         if (info.className != null) {
             pw.print(prefix); pw.print("class="); pw.println(info.className);
@@ -324,15 +351,12 @@
                 pw.print(" setRaw="); pw.print(setRawAdj);
                 pw.print(" cur="); pw.print(curAdj);
                 pw.print(" set="); pw.println(setAdj);
-        pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup);
+        pw.print(prefix); pw.print("mCurSchedGroup="); pw.print(mCurSchedGroup);
                 pw.print(" setSchedGroup="); pw.print(setSchedGroup);
                 pw.print(" systemNoUi="); pw.print(systemNoUi);
                 pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
-        if (vrThreadTid != 0) {
-            pw.print(prefix); pw.print("vrThreadTid="); pw.println(vrThreadTid);
-        }
         pw.print(prefix); pw.print("curProcState="); pw.print(curProcState);
-                pw.print(" repProcState="); pw.print(repProcState);
+                pw.print(" mRepProcState="); pw.print(mRepProcState);
                 pw.print(" pssProcState="); pw.print(pssProcState);
                 pw.print(" setProcState="); pw.print(setProcState);
                 pw.print(" lastStateTime=");
@@ -349,8 +373,8 @@
                     pw.print(" hasOverlayUi="); pw.print(hasOverlayUi);
                     pw.print(" runningRemoteAnimation="); pw.println(runningRemoteAnimation);
         }
-        if (foregroundServices || forcingToImportant != null) {
-            pw.print(prefix); pw.print("foregroundServices="); pw.print(foregroundServices);
+        if (mHasForegroundServices || forcingToImportant != null) {
+            pw.print(prefix); pw.print("mHasForegroundServices="); pw.print(mHasForegroundServices);
                     pw.print(" forcingToImportant="); pw.println(forcingToImportant);
         }
         if (reportedInteraction || fgInteractionTime != 0) {
@@ -366,8 +390,8 @@
             }
             pw.println();
         }
-        if (persistent || removed) {
-            pw.print(prefix); pw.print("persistent="); pw.print(persistent);
+        if (mPersistent || removed) {
+            pw.print(prefix); pw.print("persistent="); pw.print(mPersistent);
                     pw.print(" removed="); pw.println(removed);
         }
         if (hasClientActivities || foregroundActivities || repForegroundActivities) {
@@ -407,16 +431,16 @@
                     pw.print(" killedByAm="); pw.print(killedByAm);
                     pw.print(" waitingToKill="); pw.println(waitingToKill);
         }
-        if (debugging || crashing || crashDialog != null || notResponding
+        if (debugging || mCrashing || crashDialog != null || mNotResponding
                 || anrDialog != null || bad) {
             pw.print(prefix); pw.print("debugging="); pw.print(debugging);
-                    pw.print(" crashing="); pw.print(crashing);
+                    pw.print(" mCrashing="); pw.print(mCrashing);
                     pw.print(" "); pw.print(crashDialog);
-                    pw.print(" notResponding="); pw.print(notResponding);
+                    pw.print(" mNotResponding="); pw.print(mNotResponding);
                     pw.print(" " ); pw.print(anrDialog);
                     pw.print(" bad="); pw.print(bad);
 
-                    // crashing or notResponding is always set before errorReportReceiver
+                    // mCrashing or mNotResponding is always set before errorReportReceiver
                     if (errorReportReceiver != null) {
                         pw.print(" errorReportReceiver=");
                         pw.print(errorReportReceiver.flattenToShortString());
@@ -431,18 +455,7 @@
             pw.print(prefix); pw.print("isolatedEntryPointArgs=");
             pw.println(Arrays.toString(isolatedEntryPointArgs));
         }
-        if (activities.size() > 0) {
-            pw.print(prefix); pw.println("Activities:");
-            for (int i=0; i<activities.size(); i++) {
-                pw.print(prefix); pw.print("  - "); pw.println(activities.get(i));
-            }
-        }
-        if (recentTasks.size() > 0) {
-            pw.print(prefix); pw.println("Recent Tasks:");
-            for (int i=0; i<recentTasks.size(); i++) {
-                pw.print(prefix); pw.print("  - "); pw.println(recentTasks.get(i));
-            }
-        }
+        mWindowProcessController.dump(pw, prefix);
         if (services.size() > 0) {
             pw.print(prefix); pw.println("Services:");
             for (int i=0; i<services.size(); i++) {
@@ -498,17 +511,20 @@
         uid = _uid;
         userId = UserHandle.getUserId(_uid);
         processName = _processName;
-        pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
         maxAdj = ProcessList.UNKNOWN_ADJ;
         curRawAdj = setRawAdj = ProcessList.INVALID_ADJ;
         curAdj = setAdj = verifiedAdj = ProcessList.INVALID_ADJ;
-        persistent = false;
+        mPersistent = false;
         removed = false;
         lastStateTime = lastPssTime = nextPssTime = SystemClock.uptimeMillis();
+        mWindowProcessController = new WindowProcessController(
+                mService.mActivityTaskManager, info, processName, uid, userId, this, this);
+        pkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
     }
 
     public void setPid(int _pid) {
         pid = _pid;
+        mWindowProcessController.setPid(pid);
         procStatFile = null;
         shortStringName = null;
         stringName = null;
@@ -519,7 +535,7 @@
             final ProcessState origBase = baseProcessTracker;
             if (origBase != null) {
                 origBase.setState(ProcessStats.STATE_NOTHING,
-                        tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
+                        tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList);
                 origBase.makeInactive();
             }
             baseProcessTracker = tracker.getProcessStateLocked(info.packageName, uid,
@@ -538,15 +554,17 @@
             }
         }
         thread = _thread;
+        mWindowProcessController.setThread(thread);
     }
 
     public void makeInactive(ProcessStatsService tracker) {
         thread = null;
+        mWindowProcessController.setThread(null);
         final ProcessState origBase = baseProcessTracker;
         if (origBase != null) {
             if (origBase != null) {
                 origBase.setState(ProcessStats.STATE_NOTHING,
-                        tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
+                        tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList);
                 origBase.makeInactive();
             }
             baseProcessTracker = null;
@@ -560,11 +578,24 @@
         }
     }
 
-    public void clearRecentTasks() {
-        for (int i = recentTasks.size() - 1; i >= 0; i--) {
-            recentTasks.get(i).clearRootProcess();
-        }
-        recentTasks.clear();
+    boolean hasActivities() {
+        return mWindowProcessController.hasActivities();
+    }
+
+    void clearActivities() {
+        mWindowProcessController.clearActivities();
+    }
+
+    boolean hasActivitiesOrRecentTasks() {
+        return mWindowProcessController.hasActivitiesOrRecentTasks();
+    }
+
+    boolean hasRecentTasks() {
+        return mWindowProcessController.hasRecentTasks();
+    }
+
+    void clearRecentTasks() {
+        mWindowProcessController.clearRecentTasks();
     }
 
     /**
@@ -572,12 +603,8 @@
      * to the user. See HistoryRecord.isInterestingToUserLocked()
      */
     public boolean isInterestingToUserLocked() {
-        final int size = activities.size();
-        for (int i = 0 ; i < size ; i++) {
-            ActivityRecord r = activities.get(i);
-            if (r.isInterestingToUserLocked()) {
-                return true;
-            }
+        if (mWindowProcessController.isInterestingToUser()) {
+            return true;
         }
 
         final int servicesSize = services.size();
@@ -590,14 +617,6 @@
         return false;
     }
 
-    public void stopFreezingAllLocked() {
-        int i = activities.size();
-        while (i > 0) {
-            i--;
-            activities.get(i).stopFreezingScreenLocked(true);
-        }
-    }
-
     public void unlinkDeathRecipient() {
         if (deathRecipient != null && thread != null) {
             thread.asBinder().unlinkToDeath(deathRecipient, 0);
@@ -676,7 +695,7 @@
             } else {
                 pendingStart = false;
             }
-            if (!persistent) {
+            if (!mPersistent) {
                 killed = true;
                 killedByAm = true;
             }
@@ -697,7 +716,7 @@
                 proto.write(ProcessRecordProto.ISOLATED_APP_ID, UserHandle.getAppId(uid));
             }
         }
-        proto.write(ProcessRecordProto.PERSISTENT, persistent);
+        proto.write(ProcessRecordProto.PERSISTENT, mPersistent);
         proto.end(token);
     }
 
@@ -806,8 +825,8 @@
     }
 
     public void forceProcessStateUpTo(int newState) {
-        if (repProcState > newState) {
-            curProcState = repProcState = newState;
+        if (mRepProcState > newState) {
+            curProcState = mRepProcState = newState;
         }
     }
 
@@ -819,7 +838,7 @@
         if (baseProcessTracker != null) {
             long now = SystemClock.uptimeMillis();
             baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
-                    tracker.getMemFactorLocked(), now, pkgList);
+                    tracker.getMemFactorLocked(), now, pkgList.mPkgList);
             if (N != 1) {
                 for (int i=0; i<N; i++) {
                     ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
@@ -856,4 +875,128 @@
         }
         return list;
     }
+
+    WindowProcessController getWindowProcessController() {
+        return mWindowProcessController;
+    }
+
+    void setCurrentSchedulingGroup(int curSchedGroup) {
+        mCurSchedGroup = curSchedGroup;
+        mWindowProcessController.setCurrentSchedulingGroup(curSchedGroup);
+    }
+
+    int getCurrentSchedulingGroup() {
+        return mCurSchedGroup;
+    }
+
+    void setReportedProcState(int repProcState) {
+        mRepProcState = repProcState;
+        mWindowProcessController.setReportedProcState(repProcState);
+    }
+
+    int getReportedProcState() {
+        return mRepProcState;
+    }
+
+    void setCrashing(boolean crashing) {
+        mCrashing = crashing;
+        mWindowProcessController.setCrashing(crashing);
+    }
+
+    boolean isCrashing() {
+        return mCrashing;
+    }
+
+    void setNotResponding(boolean notResponding) {
+        mNotResponding = notResponding;
+        mWindowProcessController.setNotResponding(notResponding);
+    }
+
+    boolean isNotResponding() {
+        return mNotResponding;
+    }
+
+    void setPersistent(boolean persistent) {
+        mPersistent = persistent;
+        mWindowProcessController.setPersistent(persistent);
+    }
+
+    boolean isPersistent() {
+        return mPersistent;
+    }
+
+    public void setRequiredAbi(String requiredAbi) {
+        mRequiredAbi = requiredAbi;
+        mWindowProcessController.setRequiredAbi(requiredAbi);
+    }
+
+    String getRequiredAbi() {
+        return mRequiredAbi;
+    }
+
+    void setHasForegroundServices(boolean hasForegroundServices) {
+        mHasForegroundServices = hasForegroundServices;
+        mWindowProcessController.setHasForegroundServices(hasForegroundServices);
+    }
+
+    boolean hasForegroundServices() {
+        return mHasForegroundServices;
+    }
+
+    @Override
+    public void clearProfilerIfNeeded() {
+        synchronized (mService) {
+            if (mService.mProfileProc == null || mService.mProfilerInfo == null
+                    || mService.mProfileProc != this) {
+                return;
+            }
+            mService.clearProfilerLocked();
+        }
+    }
+
+    @Override
+    public void updateServiceConnectionActivities() {
+        synchronized (mService) {
+            mService.mServices.updateServiceConnectionActivitiesLocked(this);
+        }
+    }
+
+    @Override
+    public void setPendingUiClean(boolean pendingUiClean) {
+        synchronized (mService) {
+            this.pendingUiClean = true;
+        }
+    }
+
+    @Override
+    public void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
+        synchronized (mService) {
+            pendingUiClean = true;
+            forceProcessStateUpTo(newState);
+        }
+    }
+
+    @Override
+    public void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru,
+            boolean activityChange, boolean updateOomAdj) {
+        synchronized (mService) {
+            if (updateServiceConnectionActivities) {
+                mService.mServices.updateServiceConnectionActivitiesLocked(this);
+            }
+            if (updateLru) {
+                mService.updateLruProcessLocked(this, activityChange, null);
+            }
+            if (updateOomAdj) {
+                mService.updateOomAdjLocked();
+            }
+        }
+    }
+
+    @Override
+    public void setRemoved(boolean removed) {
+        synchronized (mService) {
+            this.removed = removed;
+        }
+    }
+
 }
diff --git a/services/core/java/com/android/server/am/ProviderMap.java b/services/core/java/com/android/server/am/ProviderMap.java
index 2f52002..29c1657 100644
--- a/services/core/java/com/android/server/am/ProviderMap.java
+++ b/services/core/java/com/android/server/am/ProviderMap.java
@@ -32,7 +32,6 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -203,7 +202,7 @@
                         && (filterByClasses == null
                             || filterByClasses.contains(provider.name.getClassName())));
             if (sameComponent
-                    && (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
+                    && (provider.proc == null || evenPersistent || !provider.proc.isPersistent())) {
                 if (!doit) {
                     return true;
                 }
diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java
index b87b948..fef3b86 100644
--- a/services/core/java/com/android/server/am/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/am/SafeActivityOptions.java
@@ -117,7 +117,7 @@
      * @param callerApp The record of the caller.
      */
     ActivityOptions getOptions(@Nullable Intent intent, @Nullable ActivityInfo aInfo,
-            @Nullable ProcessRecord callerApp,
+            @Nullable WindowProcessController callerApp,
             ActivityStackSupervisor supervisor) throws SecurityException {
         if (mOriginalOptions != null) {
             checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions,
@@ -186,7 +186,7 @@
     }
 
     private void checkPermissions(@Nullable Intent intent, @Nullable ActivityInfo aInfo,
-            @Nullable ProcessRecord callerApp, ActivityStackSupervisor supervisor,
+            @Nullable WindowProcessController callerApp, ActivityStackSupervisor supervisor,
             ActivityOptions options, int callingPid, int callingUid) {
         // If a launch task id is specified, then ensure that the caller is the recents
         // component or has the START_TASKS_FROM_RECENTS permission
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index ba012ab..c8ffdb1 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -264,7 +264,7 @@
     /** The process that had previously hosted the root activity of this task.
      * Used to know that we should try harder to keep this process around, in case the
      * user wants to return to it. */
-    private ProcessRecord mRootProcess;
+    private WindowProcessController mRootProcess;
 
     /** Takes on same value as first root activity */
     boolean isPersistable = false;
@@ -1131,7 +1131,7 @@
                 // activity
                 reportOut.numRunning = 0;
             }
-            if (r.app != null && r.app.thread != null) {
+            if (r.attachedToProcess()) {
                 // Increment the number of actually running activities
                 reportOut.numRunning++;
             }
@@ -1909,18 +1909,18 @@
         }
     }
 
-    void setRootProcess(ProcessRecord proc) {
+    void setRootProcess(WindowProcessController proc) {
         clearRootProcess();
         if (intent != null &&
                 (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
             mRootProcess = proc;
-            proc.recentTasks.add(this);
+            mRootProcess.addRecentTask(this);
         }
     }
 
     void clearRootProcess() {
         if (mRootProcess != null) {
-            mRootProcess.recentTasks.remove(this);
+            mRootProcess.removeRecentTask(this);
             mRootProcess = null;
         }
     }
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 3b47844..992179a 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -41,7 +41,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.app.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.Dialog;
diff --git a/services/core/java/com/android/server/am/VrController.java b/services/core/java/com/android/server/am/VrController.java
index 45410d7..366f95a 100644
--- a/services/core/java/com/android/server/am/VrController.java
+++ b/services/core/java/com/android/server/am/VrController.java
@@ -147,14 +147,15 @@
      *
      * <p>Note: This must be called with the global ActivityManagerService lock held.
      *
-     * @param proc is the ProcessRecord of the process that entered or left the TOP_APP scheduling
-     *        group.
+     * @param proc is the WindowProcessController of the process that entered or left the TOP_APP
+     *            scheduling group.
      */
-    public void onTopProcChangedLocked(ProcessRecord proc) {
-        if (proc.curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
-            setVrRenderThreadLocked(proc.vrThreadTid, proc.curSchedGroup, true);
+    public void onTopProcChangedLocked(WindowProcessController proc) {
+        final int curSchedGroup = proc.getCurrentSchedulingGroup();
+        if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {
+            setVrRenderThreadLocked(proc.mVrThreadTid, curSchedGroup, true);
         } else {
-            if (proc.vrThreadTid == mVrRenderThreadTid) {
+            if (proc.mVrThreadTid == mVrRenderThreadTid) {
                 clearVrRenderThreadLocked(true);
             }
         }
@@ -190,7 +191,7 @@
             changed = changeVrModeLocked(vrMode, record.app);
 
             if (record.app != null) {
-                processId = record.app.pid;
+                processId = record.app.getPid();
             }
         }
 
@@ -213,9 +214,9 @@
      *
      * @param tid the tid of the thread to set, or 0 to unset the current thread.
      * @param pid the pid of the process owning the thread to set.
-     * @param proc the ProcessRecord of the process owning the thread to set.
+     * @param proc the WindowProcessController of the process owning the thread to set.
      */
-    public void setVrThreadLocked(int tid, int pid, ProcessRecord proc) {
+    public void setVrThreadLocked(int tid, int pid, WindowProcessController proc) {
         if (hasPersistentVrFlagSet()) {
             Slog.w(TAG, "VR thread cannot be set in persistent VR mode!");
             return;
@@ -230,9 +231,9 @@
         if (!inVrMode()) {
             Slog.w(TAG, "VR thread cannot be set when not in VR mode!");
         } else {
-            setVrRenderThreadLocked(tid, proc.curSchedGroup, false);
+            setVrRenderThreadLocked(tid, proc.getCurrentSchedulingGroup(), false);
         }
-        proc.vrThreadTid = (tid > 0) ? tid : 0;
+        proc.mVrThreadTid = (tid > 0) ? tid : 0;
     }
 
     /**
@@ -280,11 +281,11 @@
      * <p>Note: This must be called with the global ActivityManagerService lock held.
      *
      * @param vrMode {@code true} if the system VR mode is being enabled.
-     * @param proc the ProcessRecord of the process enabling the system VR mode.
+     * @param proc the WindowProcessController of the process enabling the system VR mode.
      *
      * @return {@code true} if our state changed.
      */
-    private boolean changeVrModeLocked(boolean vrMode, ProcessRecord proc) {
+    private boolean changeVrModeLocked(boolean vrMode, WindowProcessController proc) {
         final int oldVrState = mVrState;
 
         // This is the only place where mVrState should have its FLAG_VR_MODE setting
@@ -299,8 +300,9 @@
 
         if (changed) {
             if (proc != null) {
-                if (proc.vrThreadTid > 0) {
-                    setVrRenderThreadLocked(proc.vrThreadTid, proc.curSchedGroup, false);
+                if (proc.mVrThreadTid > 0) {
+                    setVrRenderThreadLocked(
+                            proc.mVrThreadTid, proc.getCurrentSchedulingGroup(), false);
                 }
             } else {
               clearVrRenderThreadLocked(false);
diff --git a/services/core/java/com/android/server/am/WindowProcessController.java b/services/core/java/com/android/server/am/WindowProcessController.java
new file mode 100644
index 0000000..64a273e
--- /dev/null
+++ b/services/core/java/com/android/server/am/WindowProcessController.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2018 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.am;
+
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
+
+import android.app.Activity;
+import android.app.ActivityTaskManager;
+import android.app.ActivityThread;
+import android.app.IApplicationThread;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.os.RemoteException;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.app.HeavyWeightSwitcherActivity;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.internal.util.function.pooled.PooledRunnable;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * The Activity Manager (AM) package manages the lifecycle of processes in the system through
+ * {@link ProcessRecord}. However, it is important for the Window Manager (WM) package to be aware
+ * of the processes and their state since it affects how WM manages windows and activities. This
+ * class that allows the {@link ProcessRecord} object in the AM package to communicate important
+ * changes to its state to the WM package in a structured way. WM package also uses
+ * {@link WindowProcessListener} to request changes to the process state on the AM side.
+ * Note that public calls into this class are assumed to be originating from outside the
+ * window manager so the window manager lock is held and appropriate permissions are checked before
+ * calls are allowed to proceed.
+ */
+public class WindowProcessController {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowProcessController" : TAG_AM;
+    private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
+
+    // all about the first app in the process
+    final ApplicationInfo mInfo;
+    final String mName;
+    final int mUid;
+    // The process of this application; 0 if none
+    private volatile int mPid;
+    // user of process.
+    final int mUserId;
+    // The owner of this window process controller object. Mainly for identification when we
+    // communicate back to the activity manager side.
+    public final Object mOwner;
+    // List of packages running in the process
+    final ArraySet<String> mPkgList = new ArraySet<>();
+    private final WindowProcessListener mListener;
+    private final ActivityTaskManagerService mAtm;
+    // The actual proc...  may be null only if 'persistent' is true (in which case we are in the
+    // process of launching the app)
+    private volatile IApplicationThread mThread;
+    // Currently desired scheduling class
+    private volatile int mCurSchedGroup;
+    // Last reported process state;
+    private volatile int mRepProcState = PROCESS_STATE_NONEXISTENT;
+    // are we in the process of crashing?
+    private volatile boolean mCrashing;
+    // does the app have a not responding dialog?
+    private volatile boolean mNotResponding;
+    // always keep this application running?
+    private volatile boolean mPersistent;
+    // The ABI this process was launched with
+    private volatile String mRequiredAbi;
+    // Running any services that are foreground?
+    private volatile boolean mHasForegroundServices;
+
+    // Thread currently set for VR scheduling
+    int mVrThreadTid;
+
+    // all activities running in the process
+    private final ArrayList<ActivityRecord> mActivities = new ArrayList<>();
+    // any tasks this process had run root activities in
+    private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<>();
+
+    WindowProcessController(ActivityTaskManagerService atm, ApplicationInfo info, String name,
+            int uid, int userId, Object owner, WindowProcessListener listener) {
+        mInfo = info;
+        mName = name;
+        mUid = uid;
+        mUserId = userId;
+        mOwner = owner;
+        mListener = listener;
+        mAtm = atm;
+    }
+
+    public void setPid(int pid) {
+        mPid = pid;
+    }
+
+    int getPid() {
+        return mPid;
+    }
+
+    public void setThread(IApplicationThread thread) {
+        mThread = thread;
+    }
+
+    IApplicationThread getThread() {
+        return mThread;
+    }
+
+    boolean hasThread() {
+        return mThread != null;
+    }
+
+    public void setCurrentSchedulingGroup(int curSchedGroup) {
+        mCurSchedGroup = curSchedGroup;
+    }
+
+    int getCurrentSchedulingGroup() {
+        return mCurSchedGroup;
+    }
+
+    public void setReportedProcState(int repProcState) {
+        mRepProcState = repProcState;
+    }
+
+    int getReportedProcState() {
+        return mRepProcState;
+    }
+
+    public void setCrashing(boolean crashing) {
+        mCrashing = crashing;
+    }
+
+    boolean isCrashing() {
+        return mCrashing;
+    }
+
+    public void setNotResponding(boolean notResponding) {
+        mNotResponding = notResponding;
+    }
+
+    boolean isNotResponding() {
+        return mNotResponding;
+    }
+
+    public void setPersistent(boolean persistent) {
+        mPersistent = persistent;
+    }
+
+    boolean isPersistent() {
+        return mPersistent;
+    }
+
+    public void setHasForegroundServices(boolean hasForegroundServices) {
+        mHasForegroundServices = hasForegroundServices;
+    }
+
+    boolean hasForegroundServices() {
+        return mHasForegroundServices;
+    }
+
+    public void setRequiredAbi(String requiredAbi) {
+        mRequiredAbi = requiredAbi;
+    }
+
+    String getRequiredAbi() {
+        return mRequiredAbi;
+    }
+
+    public void addPackage(String packageName) {
+        synchronized (mAtm.mGlobalLock) {
+            mPkgList.add(packageName);
+        }
+    }
+
+    public void clearPackageList() {
+        synchronized (mAtm.mGlobalLock) {
+            mPkgList.clear();
+        }
+    }
+
+    void addActivityIfNeeded(ActivityRecord r) {
+        if (mActivities.contains(r)) {
+            return;
+        }
+        mActivities.add(r);
+    }
+
+    void removeActivity(ActivityRecord r) {
+        mActivities.remove(r);
+    }
+
+    public void clearActivities() {
+        synchronized (mAtm.mGlobalLock) {
+            mActivities.clear();
+        }
+    }
+
+    public boolean hasActivities() {
+        synchronized (mAtm.mGlobalLock) {
+            return !mActivities.isEmpty();
+        }
+    }
+
+    public boolean hasVisibleActivities() {
+        synchronized (mAtm.mGlobalLock) {
+            for (int i = mActivities.size() - 1; i >= 0; --i) {
+                final ActivityRecord r = mActivities.get(i);
+                if (r.visible) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean hasActivitiesOrRecentTasks() {
+        synchronized (mAtm.mGlobalLock) {
+            return !mActivities.isEmpty() || !mRecentTasks.isEmpty();
+        }
+    }
+
+    public void stopFreezingActivities() {
+        synchronized (mAtm.mGlobalLock) {
+            int i = mActivities.size();
+            while (i > 0) {
+                i--;
+                mActivities.get(i).stopFreezingScreenLocked(true);
+            }
+        }
+    }
+
+    public void finishActivities() {
+        synchronized (mAtm.mGlobalLock) {
+            ArrayList<ActivityRecord> activities = new ArrayList<>(mActivities);
+            for (int i = 0; i < activities.size(); i++) {
+                final ActivityRecord r = activities.get(i);
+                if (!r.finishing && r.isInStackLocked()) {
+                    r.getStack().finishActivityLocked(r, Activity.RESULT_CANCELED,
+                            null, "finish-heavy", true);
+                }
+            }
+        }
+    }
+
+    public boolean isInterestingToUser() {
+        synchronized (mAtm.mGlobalLock) {
+            final int size = mActivities.size();
+            for (int i = 0; i < size; i++) {
+                ActivityRecord r = mActivities.get(i);
+                if (r.isInterestingToUserLocked()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean hasRunningActivity(String packageName) {
+        synchronized (mAtm.mGlobalLock) {
+            for (int i = mActivities.size() - 1; i >= 0; --i) {
+                final ActivityRecord r = mActivities.get(i);
+                if (packageName.equals(r.packageName)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    public void clearPackagePreferredForHomeActivities() {
+        synchronized (mAtm.mGlobalLock) {
+            for (int i = mActivities.size() - 1; i >= 0; --i) {
+                final ActivityRecord r = mActivities.get(i);
+                if (r.isActivityTypeHome()) {
+                    Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
+                    try {
+                        ActivityThread.getPackageManager()
+                                .clearPackagePreferredActivities(r.packageName);
+                    } catch (RemoteException c) {
+                        // pm is in same process, this will never happen.
+                    }
+                }
+            }
+        }
+    }
+
+    boolean hasStartedActivity(ActivityRecord launchedActivity) {
+        for (int i = mActivities.size() - 1; i >= 0; i--) {
+            final ActivityRecord activity = mActivities.get(i);
+            if (launchedActivity == activity) {
+                continue;
+            }
+            if (!activity.stopped) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    public void updateIntentForHeavyWeightActivity(Intent intent) {
+        synchronized (mAtm.mGlobalLock) {
+            if (mActivities.isEmpty()) {
+                return;
+            }
+            ActivityRecord hist = mActivities.get(0);
+            intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP, hist.packageName);
+            intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, hist.getTask().taskId);
+        }
+    }
+
+    boolean shouldKillProcessForRemovedTask(TaskRecord tr) {
+        for (int k = 0; k < mActivities.size(); k++) {
+            final TaskRecord otherTask = mActivities.get(k).getTask();
+            if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
+                // Don't kill process(es) that has an activity in a different task that is
+                // also in recents.
+                return false;
+            }
+        }
+        return true;
+    }
+
+    ArraySet<TaskRecord> getReleaseSomeActivitiesTasks() {
+        // Examine all activities currently running in the process.
+        TaskRecord firstTask = null;
+        // Tasks is non-null only if two or more tasks are found.
+        ArraySet<TaskRecord> tasks = null;
+        if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + this);
+        for (int i = 0; i < mActivities.size(); i++) {
+            final ActivityRecord r = mActivities.get(i);
+            // First, if we find an activity that is in the process of being destroyed,
+            // then we just aren't going to do anything for now; we want things to settle
+            // down before we try to prune more activities.
+            if (r.finishing || r.isState(DESTROYING, DESTROYED)) {
+                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Abort release; already destroying: " + r);
+                return null;
+            }
+            // Don't consider any activies that are currently not in a state where they
+            // can be destroyed.
+            if (r.visible || !r.stopped || !r.haveState
+                    || r.isState(RESUMED, PAUSING, PAUSED, STOPPING)) {
+                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
+                continue;
+            }
+
+            final TaskRecord task = r.getTask();
+            if (task != null) {
+                if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task
+                        + " from " + r);
+                if (firstTask == null) {
+                    firstTask = task;
+                } else if (firstTask != task) {
+                    if (tasks == null) {
+                        tasks = new ArraySet<>();
+                        tasks.add(firstTask);
+                    }
+                    tasks.add(task);
+                }
+            }
+        }
+
+        return tasks;
+    }
+
+    public interface ComputeOomAdjCallback {
+        void onVisibleActivity();
+        void onPausedActivity();
+        void onStoppingActivity(boolean finishing);
+        void onOtherActivity();
+    }
+
+    public int computeOomAdjFromActivities(int minTaskLayer, ComputeOomAdjCallback callback) {
+        synchronized (mAtm.mGlobalLock) {
+            final int activitiesSize = mActivities.size();
+            for (int j = 0; j < activitiesSize; j++) {
+                final ActivityRecord r = mActivities.get(j);
+                if (r.app != this) {
+                    Log.e(TAG, "Found activity " + r + " in proc activity list using " + r.app
+                            + " instead of expected " + this);
+                    if (r.app == null || (r.app.mUid == mUid)) {
+                        // Only fix things up when they look sane
+                        r.setProcess(this);
+                    } else {
+                        continue;
+                    }
+                }
+                if (r.visible) {
+                    callback.onVisibleActivity();
+                    final TaskRecord task = r.getTask();
+                    if (task != null && minTaskLayer > 0) {
+                        final int layer = task.mLayerRank;
+                        if (layer >= 0 && minTaskLayer > layer) {
+                            minTaskLayer = layer;
+                        }
+                    }
+                    break;
+                } else if (r.isState(PAUSING, PAUSED)) {
+                    callback.onPausedActivity();
+                } else if (r.isState(STOPPING)) {
+                    callback.onStoppingActivity(r.finishing);
+                } else {
+                    callback.onOtherActivity();
+                }
+            }
+        }
+
+        return minTaskLayer;
+    }
+
+    void clearProfilerIfNeeded() {
+        if (mListener == null) return;
+        // Posting on handler so WM lock isn't held when we call into AM.
+        mAtm.mH.post(() -> mListener.clearProfilerIfNeeded());
+    }
+
+    void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru,
+            boolean activityChange, boolean updateOomAdj) {
+        if (mListener == null) return;
+        // Posting on handler so WM lock isn't held when we call into AM.
+        final Runnable r = PooledLambda.obtainRunnable(WindowProcessListener::updateProcessInfo,
+                mListener, updateServiceConnectionActivities, updateLru, activityChange,
+                updateOomAdj);
+        mAtm.mH.post(r);
+    }
+
+    void updateServiceConnectionActivities() {
+        if (mListener == null) return;
+        // Posting on handler so WM lock isn't held when we call into AM.
+        mAtm.mH.post(() -> mListener.updateServiceConnectionActivities());
+    }
+
+    void setPendingUiClean(boolean pendingUiClean) {
+        if (mListener == null) return;
+        // Posting on handler so WM lock isn't held when we call into AM.
+        final Runnable r = PooledLambda.obtainRunnable(
+                WindowProcessListener::setPendingUiClean, mListener, pendingUiClean);
+        mAtm.mH.post(r);
+    }
+
+    void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
+        if (mListener == null) return;
+        // Posting on handler so WM lock isn't held when we call into AM.
+        final Runnable r = PooledLambda.obtainRunnable(
+                WindowProcessListener::setPendingUiCleanAndForceProcessStateUpTo,
+                mListener, newState);
+        mAtm.mH.post(r);
+    }
+
+    void setRemoved(boolean removed) {
+        if (mListener == null) return;
+        // Posting on handler so WM lock isn't held when we call into AM.
+        final Runnable r = PooledLambda.obtainRunnable(
+                WindowProcessListener::setRemoved, mListener, removed);
+        mAtm.mH.post(r);
+    }
+
+    void addRecentTask(TaskRecord task) {
+        mRecentTasks.add(task);
+    }
+
+    void removeRecentTask(TaskRecord task) {
+        mRecentTasks.remove(task);
+    }
+
+    public boolean hasRecentTasks() {
+        synchronized (mAtm.mGlobalLock) {
+            return !mRecentTasks.isEmpty();
+        }
+    }
+
+    public void clearRecentTasks() {
+        synchronized (mAtm.mGlobalLock) {
+            for (int i = mRecentTasks.size() - 1; i >= 0; i--) {
+                mRecentTasks.get(i).clearRootProcess();
+            }
+            mRecentTasks.clear();
+        }
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        synchronized (mAtm.mGlobalLock) {
+            if (mActivities.size() > 0) {
+                pw.print(prefix); pw.println("Activities:");
+                for (int i = 0; i < mActivities.size(); i++) {
+                    pw.print(prefix); pw.print("  - "); pw.println(mActivities.get(i));
+                }
+            }
+
+            if (mRecentTasks.size() > 0) {
+                pw.println(prefix + "Recent Tasks:");
+                for (int i = 0; i < mRecentTasks.size(); i++) {
+                    pw.println(prefix + "  - " + mRecentTasks.get(i));
+                }
+            }
+
+            if (mVrThreadTid != 0) {
+                pw.print(prefix); pw.print("mVrThreadTid="); pw.println(mVrThreadTid);
+            }
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/am/WindowProcessListener.java b/services/core/java/com/android/server/am/WindowProcessListener.java
new file mode 100644
index 0000000..92e4461
--- /dev/null
+++ b/services/core/java/com/android/server/am/WindowProcessListener.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 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.am;
+
+/**
+ * Interface used by the owner/creator of a process that owns windows to listen to changes from the
+ * WM side.
+ * @see WindowProcessController
+ */
+public interface WindowProcessListener {
+
+    /** Clear the profiler record if we are currently profiling this process. */
+    void clearProfilerIfNeeded();
+
+    /** Update the service connection for this process based on activities it might have. */
+    void updateServiceConnectionActivities();
+
+    /** Set or clear flag that we would like to clean-up UI resources for this process. */
+    void setPendingUiClean(boolean pendingUiClean);
+
+    /**
+     * Set flag that we would like to clean-up UI resources for this process and force new process
+     * state.
+     */
+    void setPendingUiCleanAndForceProcessStateUpTo(int newState);
+
+    /** Update the process information. */
+    void updateProcessInfo(boolean updateServiceConnectionActivities, boolean updateLru,
+            boolean activityChange, boolean updateOomAdj);
+
+    /** Set process package been removed from device. */
+    void setRemoved(boolean removed);
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 571ee42..6971f71 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -20,8 +20,6 @@
 import static android.media.AudioManager.RINGER_MODE_NORMAL;
 import static android.media.AudioManager.RINGER_MODE_SILENT;
 import static android.media.AudioManager.RINGER_MODE_VIBRATE;
-import static android.media.AudioManager.STREAM_ALARM;
-import static android.media.AudioManager.STREAM_MUSIC;
 import static android.media.AudioManager.STREAM_SYSTEM;
 import static android.os.Process.FIRST_APPLICATION_UID;
 import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
@@ -33,7 +31,6 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.IUidObserver;
@@ -142,6 +139,7 @@
 import com.android.server.audio.AudioServiceEvents.VolumeEvent;
 import com.android.server.audio.AudioServiceEvents.WiredDevConnectEvent;
 import com.android.server.pm.UserManagerService;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import org.xmlpull.v1.XmlPullParserException;
 
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 079f3ea..65ccecd 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -21,7 +21,6 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityOptions;
-import android.app.ActivityTaskManagerInternal;
 import android.app.AppOpsManager;
 import android.app.IApplicationThread;
 import android.content.ComponentName;
@@ -42,6 +41,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index a52470d..9323040 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -20,7 +20,6 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
 import android.app.AppGlobals;
 import android.app.IApplicationThread;
 import android.app.PendingIntent;
@@ -64,6 +63,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.util.Collections;
 import java.util.List;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e5e8648..2c78303 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -60,7 +60,6 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
 import static android.content.pm.PackageManager.INSTALL_INTERNAL;
-import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
@@ -91,7 +90,6 @@
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.system.OsConstants.O_CREAT;
 import static android.system.OsConstants.O_RDWR;
-
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
 import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
 import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
@@ -123,7 +121,6 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.app.ResourcesManager;
@@ -323,11 +320,7 @@
 import com.android.server.pm.permission.PermissionsState.PermissionState;
 import com.android.server.security.VerityUtils;
 import com.android.server.storage.DeviceStorageMonitorInternal;
-
-import dalvik.system.CloseGuard;
-import dalvik.system.VMRuntime;
-
-import libcore.io.IoUtils;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -373,6 +366,10 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Predicate;
 
+import dalvik.system.CloseGuard;
+import dalvik.system.VMRuntime;
+import libcore.io.IoUtils;
+
 /**
  * Keep track of all those APKs everywhere.
  * <p>
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6e7eae1..46935f0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -27,7 +27,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
-import android.app.ActivityTaskManagerInternal;
 import android.app.IActivityManager;
 import android.app.IStopUserCallback;
 import android.app.KeyguardManager;
@@ -99,8 +98,7 @@
 import com.android.server.SystemService;
 import com.android.server.am.UserState;
 import com.android.server.storage.DeviceStorageMonitorInternal;
-
-import libcore.io.IoUtils;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -123,6 +121,8 @@
 import java.util.List;
 import java.util.Objects;
 
+import libcore.io.IoUtils;
+
 /**
  * Service for {@link UserManager}.
  *
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 71e342e..b99f8d6 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -124,7 +124,6 @@
 import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
 import static android.view.WindowManagerGlobal.ADD_OKAY;
 import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
-
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVERED;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_COVER_ABSENT;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
@@ -155,8 +154,6 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
-import android.app.ActivityTaskManagerInternal.SleepToken;
 import android.app.ActivityTaskManager;
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
@@ -275,8 +272,8 @@
 import com.android.internal.policy.PhoneWindow;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.util.ScreenShapeHelper;
+import com.android.internal.util.ScreenshotHelper;
 import com.android.internal.widget.PointerLocationView;
 import com.android.server.GestureLauncherService;
 import com.android.server.LocalServices;
@@ -286,6 +283,8 @@
 import com.android.server.policy.keyguard.KeyguardStateMonitor.StateCallback;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.vr.VrManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.DisplayFrames;
 import com.android.server.wm.WindowManagerInternal;
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index 9183b08..a16dbb7 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -3,9 +3,7 @@
 import static android.view.Display.INVALID_DISPLAY;
 
 import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
 import android.app.Vr2dDisplayProperties;
-import android.app.Service;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -14,19 +12,15 @@
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
 import android.media.ImageReader;
-import android.os.Build;
 import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
 import android.service.vr.IPersistentVrStateCallbacks;
 import android.service.vr.IVrManager;
 import android.util.Log;
 import android.view.Surface;
 
 import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
 /**
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 50bf57f..5c45afc 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -18,15 +18,13 @@
 import static android.view.Display.INVALID_DISPLAY;
 
 import android.Manifest;
-import android.app.ActivityManagerInternal;
-import android.app.ActivityTaskManagerInternal;
-import android.app.ActivityTaskManagerInternal.ScreenObserver;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.INotificationManager;
-import android.app.Vr2dDisplayProperties;
 import android.app.NotificationManager;
-import android.annotation.NonNull;
+import android.app.Vr2dDisplayProperties;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -60,30 +58,30 @@
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
-
-import com.android.server.FgThread;
-import com.android.server.wm.WindowManagerInternal;
 import android.view.inputmethod.InputMethodManagerInternal;
 
 import com.android.internal.R;
 import com.android.internal.util.DumpUtils;
+import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
-import com.android.server.utils.ManagedApplicationService.PendingEvent;
-import com.android.server.utils.ManagedApplicationService.LogEvent;
-import com.android.server.utils.ManagedApplicationService.LogFormattable;
-import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
 import com.android.server.utils.ManagedApplicationService;
 import com.android.server.utils.ManagedApplicationService.BinderChecker;
+import com.android.server.utils.ManagedApplicationService.LogEvent;
+import com.android.server.utils.ManagedApplicationService.LogFormattable;
+import com.android.server.utils.ManagedApplicationService.PendingEvent;
+import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
+import com.android.server.wm.WindowManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.lang.StringBuilder;
 import java.text.SimpleDateFormat;
-import java.util.Arrays;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
new file mode 100644
index 0000000..3885cf9
--- /dev/null
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2018 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.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.AppProtoEnums;
+import android.app.IActivityManager;
+import android.app.IApplicationThread;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.service.voice.IVoiceInteractionSession;
+import android.util.SparseIntArray;
+import android.view.RemoteAnimationAdapter;
+
+import com.android.internal.app.IVoiceInteractor;
+import com.android.server.am.WindowProcessController;
+
+import java.util.List;
+
+/**
+ * Activity Task manager local system service interface.
+ * @hide Only for use within system server
+ */
+public abstract class ActivityTaskManagerInternal {
+
+    /**
+     * Type for {@link #notifyAppTransitionStarting}: The transition was started because we drew
+     * the splash screen.
+     */
+    public static final int APP_TRANSITION_SPLASH_SCREEN =
+              AppProtoEnums.APP_TRANSITION_SPLASH_SCREEN; // 1
+
+    /**
+     * Type for {@link #notifyAppTransitionStarting}: The transition was started because we all
+     * app windows were drawn
+     */
+    public static final int APP_TRANSITION_WINDOWS_DRAWN =
+              AppProtoEnums.APP_TRANSITION_WINDOWS_DRAWN; // 2
+
+    /**
+     * Type for {@link #notifyAppTransitionStarting}: The transition was started because of a
+     * timeout.
+     */
+    public static final int APP_TRANSITION_TIMEOUT =
+              AppProtoEnums.APP_TRANSITION_TIMEOUT; // 3
+
+    /**
+     * Type for {@link #notifyAppTransitionStarting}: The transition was started because of a
+     * we drew a task snapshot.
+     */
+    public static final int APP_TRANSITION_SNAPSHOT =
+              AppProtoEnums.APP_TRANSITION_SNAPSHOT; // 4
+
+    /**
+     * Type for {@link #notifyAppTransitionStarting}: The transition was started because it was a
+     * recents animation and we only needed to wait on the wallpaper.
+     */
+    public static final int APP_TRANSITION_RECENTS_ANIM =
+            AppProtoEnums.APP_TRANSITION_RECENTS_ANIM; // 5
+
+    /**
+     * The bundle key to extract the assist data.
+     */
+    public static final String ASSIST_KEY_DATA = "data";
+
+    /**
+     * The bundle key to extract the assist structure.
+     */
+    public static final String ASSIST_KEY_STRUCTURE = "structure";
+
+    /**
+     * The bundle key to extract the assist content.
+     */
+    public static final String ASSIST_KEY_CONTENT = "content";
+
+    /**
+     * The bundle key to extract the assist receiver extras.
+     */
+    public static final String ASSIST_KEY_RECEIVER_EXTRAS = "receiverExtras";
+
+    public interface ScreenObserver {
+        void onAwakeStateChanged(boolean isAwake);
+        void onKeyguardStateChanged(boolean isShowing);
+    }
+
+    /**
+     * Sleep tokens cause the activity manager to put the top activity to sleep.
+     * They are used by components such as dreams that may hide and block interaction
+     * with underlying activities.
+     */
+    public static abstract class SleepToken {
+
+        /** Releases the sleep token. */
+        public abstract void release();
+    }
+
+    /**
+     * Acquires a sleep token for the specified display with the specified tag.
+     *
+     * @param tag A string identifying the purpose of the token (eg. "Dream").
+     * @param displayId The display to apply the sleep token to.
+     */
+    public abstract SleepToken acquireSleepToken(@NonNull String tag, int displayId);
+
+    /**
+     * Returns home activity for the specified user.
+     *
+     * @param userId ID of the user or {@link android.os.UserHandle#USER_ALL}
+     */
+    public abstract ComponentName getHomeActivityForUser(int userId);
+
+    public abstract void onLocalVoiceInteractionStarted(IBinder callingActivity,
+            IVoiceInteractionSession mSession,
+            IVoiceInteractor mInteractor);
+
+    /**
+     * Callback for window manager to let activity manager know that we are finally starting the
+     * app transition;
+     *
+     * @param reasons A map from windowing mode to a reason integer why the transition was started,
+     *                which must be one of the APP_TRANSITION_* values.
+     * @param timestamp The time at which the app transition started in
+     *                  {@link SystemClock#uptimeMillis()} timebase.
+     */
+    public abstract void notifyAppTransitionStarting(SparseIntArray reasons, long timestamp);
+
+    /**
+     * Callback for window manager to let activity manager know that the app transition was
+     * cancelled.
+     */
+    public abstract void notifyAppTransitionCancelled();
+
+    /**
+     * Callback for window manager to let activity manager know that the app transition is finished.
+     */
+    public abstract void notifyAppTransitionFinished();
+
+    /**
+     * Returns the top activity from each of the currently visible stacks. The first entry will be
+     * the focused activity.
+     */
+    public abstract List<IBinder> getTopVisibleActivities();
+
+    /**
+     * Callback for window manager to let activity manager know that docked stack changes its
+     * minimized state.
+     */
+    public abstract void notifyDockedStackMinimizedChanged(boolean minimized);
+
+    /**
+     * Start activity {@code intents} as if {@code packageName} on user {@code userId} did it.
+     *
+     * - DO NOT call it with the calling UID cleared.
+     * - All the necessary caller permission checks must be done at callsites.
+     *
+     * @return error codes used by {@link IActivityManager#startActivity} and its siblings.
+     */
+    public abstract int startActivitiesAsPackage(String packageName,
+            int userId, Intent[] intents, Bundle bOptions);
+
+    /**
+     * Start activity {@code intent} without calling user-id check.
+     *
+     * - DO NOT call it with the calling UID cleared.
+     * - The caller must do the calling user ID check.
+     *
+     * @return error codes used by {@link IActivityManager#startActivity} and its siblings.
+     */
+    public abstract int startActivityAsUser(IApplicationThread caller, String callingPackage,
+            Intent intent, @Nullable Bundle options, int userId);
+
+    /**
+     * Called when Keyguard flags might have changed.
+     *
+     * @param callback Callback to run after activity visibilities have been reevaluated. This can
+     *                 be used from window manager so that when the callback is called, it's
+     *                 guaranteed that all apps have their visibility updated accordingly.
+     */
+    public abstract void notifyKeyguardFlagsChanged(@Nullable Runnable callback);
+
+    /**
+     * Called when the trusted state of Keyguard has changed.
+     */
+    public abstract void notifyKeyguardTrustedChanged();
+
+    /**
+     * Called after virtual display Id is updated by
+     * {@link com.android.server.vr.Vr2dDisplay} with a specific
+     * {@param vr2dDisplayId}.
+     */
+    public abstract void setVr2dDisplayId(int vr2dDisplayId);
+
+    /**
+     * Set focus on an activity.
+     * @param token The IApplicationToken for the activity
+     */
+    public abstract void setFocusedActivity(IBinder token);
+
+    public abstract void registerScreenObserver(ScreenObserver observer);
+
+    /**
+     * Returns is the caller has the same uid as the Recents component
+     */
+    public abstract boolean isCallerRecents(int callingUid);
+
+    /**
+     * Returns whether the recents component is the home activity for the given user.
+     */
+    public abstract boolean isRecentsComponentHomeActivity(int userId);
+
+    /**
+     * Cancels any currently running recents animation.
+     */
+    public abstract void cancelRecentsAnimation(boolean restoreHomeStackPosition);
+
+    /**
+     * This enforces {@code func} can only be called if either the caller is Recents activity or
+     * has {@code permission}.
+     */
+    public abstract void enforceCallerIsRecentsOrHasPermission(String permission, String func);
+
+    /**
+     * Called after the voice interaction service has changed.
+     */
+    public abstract void notifyActiveVoiceInteractionServiceChanged(ComponentName component);
+
+    /**
+     * Set a uid that is allowed to bypass stopped app switches, launching an app
+     * whenever it wants.
+     *
+     * @param type Type of the caller -- unique string the caller supplies to identify itself
+     * and disambiguate with other calles.
+     * @param uid The uid of the app to be allowed, or -1 to clear the uid for this type.
+     * @param userId The user it is allowed for.
+     */
+    public abstract void setAllowAppSwitches(@NonNull String type, int uid, int userId);
+
+    /**
+     * Called when a user has been deleted. This can happen during normal device usage
+     * or just at startup, when partially removed users are purged. Any state persisted by the
+     * ActivityManager should be purged now.
+     *
+     * @param userId The user being cleaned up.
+     */
+    public abstract void onUserStopped(int userId);
+    public abstract boolean isGetTasksAllowed(String caller, int callingPid, int callingUid);
+
+    public abstract void onProcessAdded(WindowProcessController proc);
+    public abstract void onProcessRemoved(String name, int uid);
+    public abstract void onCleanUpApplicationRecord(WindowProcessController proc);
+}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index b610695..6f5fea9 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -16,13 +16,13 @@
 
 package com.android.server.wm;
 
-import static android.app.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
@@ -48,11 +48,14 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.inputmethod.InputMethodManagerInternal;
+
+import com.google.android.collect.Sets;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 import com.android.server.wm.utils.InsetUtils;
-import com.google.android.collect.Sets;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2c7ab7e..f4aebcd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -117,7 +117,6 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityTaskManager;
-import android.app.ActivityTaskManagerInternal;
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 1a8753d..aced8e4 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -16,18 +16,10 @@
 
 package com.android.server.wm;
 
-import static android.app.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
-import static android.app.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
-import static android.app.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
-
-import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
-import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
-import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
-import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
@@ -39,10 +31,17 @@
 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
 import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
 import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
 import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
 import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
 import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;