diff options
9 files changed, 210 insertions, 72 deletions
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 21760cdf02eb..419389f7abef 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.PrintWriter; 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { } 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { // Cleanup. if (newService) { - app.services.remove(r); + app.stopService(r); r.setProcess(null); } @@ -3362,7 +3361,7 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { } 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { } if (!allowRestart) { - app.services.clear(); + app.stopAllServices(); app.clearBoundClientUids(); // Make sure there are no more restarting services for this process. @@ -4920,8 +4917,8 @@ public final class ActiveServices { 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 3fdf541566a5..9b2743ca6b1d 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 @@ public class ActivityManagerService extends IActivityManager.Stub 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 b1fc0296518b..50d2cab0af81 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 @@ class AppErrors { } // 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 2d6ef81faf1c..ad858533c430 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 @@ public final class OomAdjuster { 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 @@ public final class OomAdjuster { } 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 61ebc361b6af..a1ec07cda8a8 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 @@ class ProcessRecord implements WindowProcessListener { // 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 @@ class ProcessRecord implements WindowProcessListener { 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 @@ class ProcessRecord implements WindowProcessListener { } } + /** + * 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 @@ class ProcessRecord implements WindowProcessListener { 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 @@ class ProcessRecord implements WindowProcessListener { } 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 93a757449564..02f6a696f598 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 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } 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 194ed3ec3b0e..41bd70726e71 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.INSTRUMENTATION_K 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.Context; 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio // 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio /** 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio * 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio 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 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } } + /** + * 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 7a175ca1b7f5..2983d585c45a 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 @@ public class MockingOomAdjusterTests { 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 @@ public class MockingOomAdjusterTests { 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 @@ public class MockingOomAdjusterTests { 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 @@ public class MockingOomAdjusterTests { 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 07a6179c00bd..cdf8eb4faf1d 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.mock; 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 @@ public class WindowProcessControllerTests extends ActivityTestsBase { 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(); } |