Merge "Disable activity process config override for certain display-based services." into rvc-dev am: 3b145e0b19

Change-Id: I51f9b25e72631a5a9db7405410e0ad89c3b8832d
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 21760cd..419389f 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -119,7 +119,6 @@
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Comparator;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Predicate;
@@ -1753,8 +1752,8 @@
     private void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
         boolean anyForeground = false;
         int fgServiceTypes = 0;
-        for (int i = proc.services.size() - 1; i >= 0; i--) {
-            ServiceRecord sr = proc.services.valueAt(i);
+        for (int i = proc.numberOfRunningServices() - 1; i >= 0; i--) {
+            ServiceRecord sr = proc.getRunningServiceAt(i);
             if (sr.isForeground || sr.fgRequired) {
                 anyForeground = true;
                 fgServiceTypes |= sr.foregroundServiceType;
@@ -1765,8 +1764,8 @@
 
     private void updateWhitelistManagerLocked(ProcessRecord proc) {
         proc.whitelistManager = false;
-        for (int i=proc.services.size()-1; i>=0; i--) {
-            ServiceRecord sr = proc.services.valueAt(i);
+        for (int i = proc.numberOfRunningServices() - 1; i >= 0; i--) {
+            ServiceRecord sr = proc.getRunningServiceAt(i);
             if (sr.whitelistManager) {
                 proc.whitelistManager = true;
                 break;
@@ -1802,8 +1801,8 @@
         }
 
         boolean anyClientActivities = false;
-        for (int i=proc.services.size()-1; i>=0 && !anyClientActivities; i--) {
-            ServiceRecord sr = proc.services.valueAt(i);
+        for (int i = proc.numberOfRunningServices() - 1; i >= 0 && !anyClientActivities; i--) {
+            ServiceRecord sr = proc.getRunningServiceAt(i);
             ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = sr.getConnections();
             for (int conni = connections.size() - 1; conni >= 0 && !anyClientActivities; conni--) {
                 ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
@@ -2995,7 +2994,7 @@
         r.setProcess(app);
         r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
 
-        final boolean newService = app.services.add(r);
+        final boolean newService = app.startService(r);
         bumpServiceExecutingLocked(r, execInFg, "create");
         mAm.updateLruProcessLocked(app, false, null);
         updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
@@ -3036,7 +3035,7 @@
 
                 // Cleanup.
                 if (newService) {
-                    app.services.remove(r);
+                    app.stopService(r);
                     r.setProcess(null);
                 }
 
@@ -3362,7 +3361,7 @@
             synchronized (r.stats.getBatteryStats()) {
                 r.stats.stopLaunchedLocked();
             }
-            r.app.services.remove(r);
+            r.app.stopService(r);
             r.app.updateBoundClientUids();
             if (r.whitelistManager) {
                 updateWhitelistManagerLocked(r.app);
@@ -3652,7 +3651,7 @@
             }
             if (finishing) {
                 if (r.app != null && !r.app.isPersistent()) {
-                    r.app.services.remove(r);
+                    r.app.stopService(r);
                     r.app.updateBoundClientUids();
                     if (r.whitelistManager) {
                         updateWhitelistManagerLocked(r.app);
@@ -3748,7 +3747,7 @@
                 didSomething = true;
                 Slog.i(TAG, "  Force stopping service " + service);
                 if (service.app != null && !service.app.isPersistent()) {
-                    service.app.services.remove(service);
+                    service.app.stopService(service);
                     service.app.updateBoundClientUids();
                     if (service.whitelistManager) {
                         updateWhitelistManagerLocked(service.app);
@@ -3861,24 +3860,22 @@
         if (false) {
             // XXX we are letting the client link to the service for
             // death notifications.
-            if (app.services.size() > 0) {
-                Iterator<ServiceRecord> it = app.services.iterator();
-                while (it.hasNext()) {
-                    ServiceRecord r = it.next();
-                    ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
-                    for (int conni=connections.size()-1; conni>=0; conni--) {
-                        ArrayList<ConnectionRecord> cl = connections.valueAt(conni);
-                        for (int i=0; i<cl.size(); i++) {
-                            ConnectionRecord c = cl.get(i);
-                            if (c.binding.client != app) {
-                                try {
-                                    //c.conn.connected(r.className, null);
-                                } catch (Exception e) {
-                                    // todo: this should be asynchronous!
-                                    Slog.w(TAG, "Exception thrown disconnected servce "
-                                          + r.shortInstanceName
-                                          + " from app " + app.processName, e);
-                                }
+            int numberOfRunningServices = app.numberOfRunningServices();
+            for (int sIndex = 0; sIndex < numberOfRunningServices; sIndex++) {
+                ServiceRecord r = app.getRunningServiceAt(sIndex);
+                ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+                for (int conni = connections.size() - 1; conni >= 0; conni--) {
+                    ArrayList<ConnectionRecord> cl = connections.valueAt(conni);
+                    for (int i = 0; i < cl.size(); i++) {
+                        ConnectionRecord c = cl.get(i);
+                        if (c.binding.client != app) {
+                            try {
+                                //c.conn.connected(r.className, null);
+                            } catch (Exception e) {
+                                // todo: this should be asynchronous!
+                                Slog.w(TAG, "Exception thrown disconnected servce "
+                                        + r.shortInstanceName
+                                        + " from app " + app.processName, e);
                             }
                         }
                     }
@@ -3897,13 +3894,13 @@
         app.whitelistManager = false;
 
         // Clear app state from services.
-        for (int i = app.services.size() - 1; i >= 0; i--) {
-            ServiceRecord sr = app.services.valueAt(i);
+        for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) {
+            ServiceRecord sr = app.getRunningServiceAt(i);
             synchronized (sr.stats.getBatteryStats()) {
                 sr.stats.stopLaunchedLocked();
             }
             if (sr.app != app && sr.app != null && !sr.app.isPersistent()) {
-                sr.app.services.remove(sr);
+                sr.app.stopService(sr);
                 sr.app.updateBoundClientUids();
             }
             sr.setProcess(null);
@@ -3962,13 +3959,13 @@
         ServiceMap smap = getServiceMapLocked(app.userId);
 
         // Now do remaining service cleanup.
-        for (int i=app.services.size()-1; i>=0; i--) {
-            ServiceRecord sr = app.services.valueAt(i);
+        for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) {
+            ServiceRecord sr = app.getRunningServiceAt(i);
 
             // Unless the process is persistent, this process record is going away,
             // so make sure the service is cleaned out of it.
             if (!app.isPersistent()) {
-                app.services.removeAt(i);
+                app.stopService(sr);
                 app.updateBoundClientUids();
             }
 
@@ -4018,7 +4015,7 @@
         }
 
         if (!allowRestart) {
-            app.services.clear();
+            app.stopAllServices();
             app.clearBoundClientUids();
 
             // Make sure there are no more restarting services for this process.
@@ -4920,8 +4917,8 @@
             if (pr.uid != uid) {
                 continue;
             }
-            for (int j = pr.services.size() - 1; j >= 0; j--) {
-                ServiceRecord r = pr.services.valueAt(j);
+            for (int j = pr.numberOfRunningServices() - 1; j >= 0; j--) {
+                ServiceRecord r = pr.getRunningServiceAt(j);
                 if (!r.isForeground) {
                     continue;
                 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3fdf541..9b2743c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18172,7 +18172,7 @@
         for (int i = mProcessList.mRemovedProcesses.size() - 1; i >= 0; i--) {
             final ProcessRecord app = mProcessList.mRemovedProcesses.get(i);
             if (!app.hasActivitiesOrRecentTasks()
-                    && app.curReceivers.isEmpty() && app.services.size() == 0) {
+                    && app.curReceivers.isEmpty() && app.numberOfRunningServices() == 0) {
                 Slog.i(
                     TAG, "Exiting empty application process "
                     + app.toShortString() + " ("
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index b1fc029..50d2cab 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -702,10 +702,10 @@
         }
 
         // Bump up the crash count of any services currently running in the proc.
-        for (int i = app.services.size() - 1; i >= 0; i--) {
+        for (int i = app.numberOfRunningServices() - 1; i >= 0; i--) {
             // Any services running in the application need to be placed
             // back in the pending list.
-            ServiceRecord sr = app.services.valueAt(i);
+            ServiceRecord sr = app.getRunningServiceAt(i);
             // If the service was restarted a while ago, then reset crash count, else increment it.
             if (now > sr.restartTime + ProcessList.MIN_CRASH_INTERVAL) {
                 sr.crashCount = 1;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 2d6ef81..ad85853 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -837,7 +837,8 @@
                         break;
                 }
 
-                if (app.isolated && app.services.size() <= 0 && app.isolatedEntryPoint == null) {
+                if (app.isolated && app.numberOfRunningServices() <= 0
+                        && app.isolatedEntryPoint == null) {
                     // If this is an isolated process, there are no services
                     // running in it, and it's not a special process with a
                     // custom entry point, then the process is no longer
@@ -1446,12 +1447,12 @@
         }
 
         int capabilityFromFGS = 0; // capability from foreground service.
-        for (int is = app.services.size() - 1;
+        for (int is = app.numberOfRunningServices() - 1;
                 is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                         || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                         || procState > PROCESS_STATE_TOP);
                 is--) {
-            ServiceRecord s = app.services.valueAt(is);
+            ServiceRecord s = app.getRunningServiceAt(is);
             if (s.startRequested) {
                 app.hasStartedServices = true;
                 if (procState > PROCESS_STATE_SERVICE) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 61ebc36..a1ec07c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -261,9 +261,9 @@
     // Controller for error dialogs
     private final ErrorDialogController mDialogController = new ErrorDialogController();
     // Controller for driving the process state on the window manager side.
-    final private WindowProcessController mWindowProcessController;
+    private final WindowProcessController mWindowProcessController;
     // all ServiceRecord running in this process
-    final ArraySet<ServiceRecord> services = new ArraySet<>();
+    private final ArraySet<ServiceRecord> mServices = new ArraySet<>();
     // services that are currently executing code (need to remain foreground).
     final ArraySet<ServiceRecord> executingServices = new ArraySet<>();
     // All ConnectionRecord this process holds
@@ -577,10 +577,10 @@
             pw.println(Arrays.toString(isolatedEntryPointArgs));
         }
         mWindowProcessController.dump(pw, prefix);
-        if (services.size() > 0) {
+        if (mServices.size() > 0) {
             pw.print(prefix); pw.println("Services:");
-            for (int i=0; i<services.size(); i++) {
-                pw.print(prefix); pw.print("  - "); pw.println(services.valueAt(i));
+            for (int i = 0; i < mServices.size(); i++) {
+                pw.print(prefix); pw.print("  - "); pw.println(mServices.valueAt(i));
             }
         }
         if (executingServices.size() > 0) {
@@ -735,6 +735,60 @@
         }
     }
 
+    /**
+     * Records a service as running in the process. Note that this method does not actually start
+     * the service, but records the service as started for bookkeeping.
+     *
+     * @return true if the service was added, false otherwise.
+     */
+    boolean startService(ServiceRecord record) {
+        if (record == null) {
+            return false;
+        }
+        boolean added = mServices.add(record);
+        if (added && record.serviceInfo != null) {
+            mWindowProcessController.onServiceStarted(record.serviceInfo);
+        }
+        return added;
+    }
+
+    /**
+     * Records a service as stopped. Note that like {@link #startService(ServiceRecord)} this method
+     * does not actually stop the service, but records the service as stopped for bookkeeping.
+     *
+     * @return true if the service was removed, false otherwise.
+     */
+    boolean stopService(ServiceRecord record) {
+        return mServices.remove(record);
+    }
+
+    /**
+     * The same as calling {@link #stopService(ServiceRecord)} on all current running services.
+     */
+    void stopAllServices() {
+        mServices.clear();
+    }
+
+    /**
+     * Returns the number of services added with {@link #startService(ServiceRecord)} and not yet
+     * removed by a call to {@link #stopService(ServiceRecord)} or {@link #stopAllServices()}.
+     *
+     * @see #startService(ServiceRecord)
+     * @see #stopService(ServiceRecord)
+     */
+    int numberOfRunningServices() {
+        return mServices.size();
+    }
+
+    /**
+     * Returns the service at the specified {@code index}.
+     *
+     * @see #numberOfRunningServices()
+     */
+    ServiceRecord getRunningServiceAt(int index) {
+        return mServices.valueAt(index);
+    }
+
     void setCached(boolean cached) {
         if (mCached != cached) {
             mCached = cached;
@@ -768,9 +822,9 @@
             return true;
         }
 
-        final int servicesSize = services.size();
+        final int servicesSize = mServices.size();
         for (int i = 0; i < servicesSize; i++) {
-            ServiceRecord r = services.valueAt(i);
+            ServiceRecord r = mServices.valueAt(i);
             if (r.isForeground) {
                 return true;
             }
@@ -1289,16 +1343,16 @@
     }
 
     void updateBoundClientUids() {
-        if (services.isEmpty()) {
+        if (mServices.isEmpty()) {
             clearBoundClientUids();
             return;
         }
         // grab a set of clientUids of all connections of all services
         ArraySet<Integer> boundClientUids = new ArraySet<>();
-        final int K = services.size();
-        for (int j = 0; j < K; j++) {
+        final int serviceCount = mServices.size();
+        for (int j = 0; j < serviceCount; j++) {
             ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
-                    services.valueAt(j).getConnections();
+                    mServices.valueAt(j).getConnections();
             final int N = conns.size();
             for (int conni = 0; conni < N; conni++) {
                 ArrayList<ConnectionRecord> c = conns.valueAt(conni);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 93a7574..02f6a69 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -6604,7 +6604,6 @@
                     }
                     return;
                 }
-                process.mIsImeProcess = true;
                 process.registerDisplayConfigurationListener(displayContent);
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 194ed3e..41bd707 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -40,6 +40,7 @@
 import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityThread;
@@ -50,6 +51,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
 import android.os.Build;
 import android.os.Message;
@@ -165,7 +167,8 @@
     // Thread currently set for VR scheduling
     int mVrThreadTid;
 
-    boolean mIsImeProcess;
+    // Whether this process has ever started a service with the BIND_INPUT_METHOD permission.
+    private volatile boolean mHasImeService;
 
     // all activities running in the process
     private final ArrayList<ActivityRecord> mActivities = new ArrayList<>();
@@ -187,6 +190,8 @@
     // Registered display id as a listener to override config change
     private int mDisplayId;
     private ActivityRecord mConfigActivityRecord;
+    // Whether the activity config override is allowed for this process.
+    private volatile boolean mIsActivityConfigOverrideAllowed = true;
     /**
      * Activities that hosts some UI drawn by the current process. The activities live
      * in another process. This is used to check if the process is currently showing anything
@@ -201,9 +206,6 @@
     /** Whether our process is currently running a {@link IRemoteAnimationRunner} */
     private boolean mRunningRemoteAnimation;
 
-    /** Whether this process is owned by the System UI package. */
-    final boolean mIsSysUiPackage;
-
     public WindowProcessController(@NonNull ActivityTaskManagerService atm, ApplicationInfo info,
             String name, int uid, int userId, Object owner, WindowProcessListener listener) {
         mInfo = info;
@@ -215,8 +217,13 @@
         mAtm = atm;
         mDisplayId = INVALID_DISPLAY;
 
-        mIsSysUiPackage = info.packageName.equals(
+        boolean isSysUiPackage = info.packageName.equals(
                 mAtm.getSysUiServiceComponentLocked().getPackageName());
+        if (isSysUiPackage || mUid == Process.SYSTEM_UID) {
+            // This is a system owned process and should not use an activity config.
+            // TODO(b/151161907): Remove after support for display-independent (raw) SysUi configs.
+            mIsActivityConfigOverrideAllowed = false;
+        }
 
         onConfigurationChanged(atm.getGlobalConfiguration());
     }
@@ -1095,9 +1102,7 @@
      * always track the configuration of the non-finishing activity last added to the process.
      */
     private void updateActivityConfigurationListener() {
-        if (mIsSysUiPackage || mUid == Process.SYSTEM_UID) {
-            // This is a system owned process and should not use an activity config.
-            // TODO(b/151161907): Remove after support for display-independent (raw) SysUi configs.
+        if (!mIsActivityConfigOverrideAllowed) {
             return;
         }
 
@@ -1132,7 +1137,7 @@
         final Configuration config = getConfiguration();
         if (mLastReportedConfiguration.diff(config) == 0) {
             // Nothing changed.
-            if (Build.IS_DEBUGGABLE && mIsImeProcess) {
+            if (Build.IS_DEBUGGABLE && mHasImeService) {
                 // TODO (b/135719017): Temporary log for debugging IME service.
                 Slog.w(TAG_CONFIGURATION, "Current config: " + config
                         + " unchanged for IME proc " + mName);
@@ -1156,7 +1161,7 @@
 
     private void dispatchConfigurationChange(Configuration config) {
         if (mThread == null) {
-            if (Build.IS_DEBUGGABLE && mIsImeProcess) {
+            if (Build.IS_DEBUGGABLE && mHasImeService) {
                 // TODO (b/135719017): Temporary log for debugging IME service.
                 Slog.w(TAG_CONFIGURATION, "Unable to send config for IME proc " + mName
                         + ": no app thread");
@@ -1166,7 +1171,7 @@
         if (DEBUG_CONFIGURATION) {
             Slog.v(TAG_CONFIGURATION, "Sending to proc " + mName + " new config " + config);
         }
-        if (Build.IS_DEBUGGABLE && mIsImeProcess) {
+        if (Build.IS_DEBUGGABLE && mHasImeService) {
             // TODO (b/135719017): Temporary log for debugging IME service.
             Slog.v(TAG_CONFIGURATION, "Sending to IME proc " + mName + " new config " + config);
         }
@@ -1286,6 +1291,35 @@
         }
     }
 
+    /**
+     * Called to notify {@link WindowProcessController} of a started service.
+     *
+     * @param serviceInfo information describing the started service.
+     */
+    public void onServiceStarted(ServiceInfo serviceInfo) {
+        String permission = serviceInfo.permission;
+        if (permission == null) {
+            return;
+        }
+
+        // TODO: Audit remaining services for disabling activity override (Wallpaper, Dream, etc).
+        switch (permission) {
+            case Manifest.permission.BIND_INPUT_METHOD:
+                mHasImeService = true;
+                // Fall-through
+            case Manifest.permission.BIND_ACCESSIBILITY_SERVICE:
+            case Manifest.permission.BIND_VOICE_INTERACTION:
+                // We want to avoid overriding the config of these services with that of the
+                // activity as it could lead to incorrect display metrics. For ex, IME services
+                // expect their config to match the config of the display with the IME window
+                // showing.
+                mIsActivityConfigOverrideAllowed = false;
+                break;
+            default:
+                break;
+        }
+    }
+
     @HotPath(caller = HotPath.OOM_ADJUSTMENT)
     public void onTopProcChanged() {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 7a175ca1..2983d58 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -541,7 +541,7 @@
         doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
         s.startRequested = true;
         s.lastActivity = SystemClock.uptimeMillis();
-        app.services.add(s);
+        app.startService(s);
         sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
         sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
 
@@ -585,7 +585,7 @@
         doReturn(new ArrayMap<IBinder, ArrayList<ConnectionRecord>>()).when(s).getConnections();
         s.startRequested = true;
         s.lastActivity = SystemClock.uptimeMillis();
-        app.services.add(s);
+        app.startService(s);
         sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
         sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
 
@@ -1593,7 +1593,7 @@
         s.app = app3;
         setFieldValue(ServiceRecord.class, s, "connections",
                 new ArrayMap<IBinder, ArrayList<ConnectionRecord>>());
-        app3.services.add(s);
+        app3.startService(s);
         doCallRealMethod().when(s).getConnections();
         s.startRequested = true;
         s.lastActivity = now;
@@ -1698,7 +1698,7 @@
             record.app = service;
             setFieldValue(ServiceRecord.class, record, "connections",
                     new ArrayMap<IBinder, ArrayList<ConnectionRecord>>());
-            service.services.add(record);
+            service.startService(record);
             doCallRealMethod().when(record).getConnections();
         }
         AppBindRecord binding = new AppBindRecord(record, null, client);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 07a6179..cdf8eb4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -28,9 +28,11 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.when;
 
+import android.Manifest;
 import android.app.IApplicationThread;
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
 import android.platform.test.annotations.Presubmit;
 
@@ -200,6 +202,57 @@
         assertFalse(wpc.registeredForActivityConfigChanges());
     }
 
+    @Test
+    public void testActivityNotOverridingImeProcessConfig() {
+        ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.permission = Manifest.permission.BIND_INPUT_METHOD;
+        // Notify WPC that this process has started an IME service.
+        mWpc.onServiceStarted(serviceInfo);
+
+        final ActivityRecord activity = new ActivityBuilder(mService)
+                .setCreateTask(true)
+                .setUseProcess(mWpc)
+                .build();
+
+        mWpc.addActivityIfNeeded(activity);
+        // IME processes should not be registered for activity config changes.
+        assertFalse(mWpc.registeredForActivityConfigChanges());
+    }
+
+    @Test
+    public void testActivityNotOverridingAllyProcessConfig() {
+        ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.permission = Manifest.permission.BIND_ACCESSIBILITY_SERVICE;
+        // Notify WPC that this process has started an ally service.
+        mWpc.onServiceStarted(serviceInfo);
+
+        final ActivityRecord activity = new ActivityBuilder(mService)
+                .setCreateTask(true)
+                .setUseProcess(mWpc)
+                .build();
+
+        mWpc.addActivityIfNeeded(activity);
+        // Ally processes should not be registered for activity config changes.
+        assertFalse(mWpc.registeredForActivityConfigChanges());
+    }
+
+    @Test
+    public void testActivityNotOverridingVoiceInteractionProcessConfig() {
+        ServiceInfo serviceInfo = new ServiceInfo();
+        serviceInfo.permission = Manifest.permission.BIND_VOICE_INTERACTION;
+        // Notify WPC that this process has started an voice interaction service.
+        mWpc.onServiceStarted(serviceInfo);
+
+        final ActivityRecord activity = new ActivityBuilder(mService)
+                .setCreateTask(true)
+                .setUseProcess(mWpc)
+                .build();
+
+        mWpc.addActivityIfNeeded(activity);
+        // Voice interaction service processes should not be registered for activity config changes.
+        assertFalse(mWpc.registeredForActivityConfigChanges());
+    }
+
     private TestDisplayContent createTestDisplayContentInContainer() {
         return new TestDisplayContent.Builder(mService, 1000, 1500).build();
     }