diff options
| author | 2018-11-05 05:12:46 -0800 | |
|---|---|---|
| committer | 2018-11-07 07:09:35 -0800 | |
| commit | 1f5e53d4a613488ae12a7d17fedfbf702bf2bffa (patch) | |
| tree | 4929f7b165a7f9f8d88fb5f0baf2fc8712216601 | |
| parent | 38762429f999034ad8a87c8d90963ec6a2f68fad (diff) | |
Unify Activities and Windows under one lock (38/n)
Final step before we actually start unifing the hierarchy is to have
activity and window manager under one lock. This CL makes it so.
Note, that there are probably areas where this change might lead to dealock
however we can fix those areas as we discover them.
Test: Existing tests pass
Bug: 80414790
Change-Id: Ie4b71d4ceb986256482031a99065b8d2ef60ebe8
16 files changed, 370 insertions, 300 deletions
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 9cc550daa5a7..d1b56e9afa4e 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -43,6 +43,7 @@ import android.util.Slog; import com.android.internal.os.ZygoteConnectionConstants; import com.android.server.am.ActivityManagerService; +import com.android.server.wm.SurfaceAnimationThread; import java.io.File; import java.io.FileWriter; @@ -280,6 +281,12 @@ public class Watchdog extends Thread { // And the display thread. mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(), "display thread", DEFAULT_TIMEOUT)); + // And the animation thread. + mHandlerCheckers.add(new HandlerChecker(AnimationThread.getHandler(), + "animation thread", DEFAULT_TIMEOUT)); + // And the surface animation thread. + mHandlerCheckers.add(new HandlerChecker(SurfaceAnimationThread.getHandler(), + "surface animation thread", DEFAULT_TIMEOUT)); // Initialize monitor for Binder threads. addMonitor(new BinderThreadMonitor()); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 7ea7e1a8241e..c45eaf67d3dc 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1134,9 +1134,46 @@ public class ActivityManagerService extends IActivityManager.Stub boolean mOrigWaitForDebugger = false; boolean mAlwaysFinishActivities = false; - String mProfileApp = null; - ProcessRecord mProfileProc = null; - ProfilerInfo mProfilerInfo = null; + class ProfileData { + private String mProfileApp = null; + private ProcessRecord mProfileProc = null; + private ProfilerInfo mProfilerInfo = null; + + void setProfileApp(String profileApp) { + mProfileApp = profileApp; + if (mAtmInternal != null) { + mAtmInternal.setProfileApp(profileApp); + } + } + + String getProfileApp() { + return mProfileApp; + } + + void setProfileProc(ProcessRecord profileProc) { + mProfileProc = profileProc; + if (mAtmInternal != null) { + mAtmInternal.setProfileProc( + profileProc.getWindowProcessController()); + } + } + + ProcessRecord getProfileProc() { + return mProfileProc; + } + + void setProfilerInfo(ProfilerInfo profilerInfo) { + mProfilerInfo = profilerInfo; + if (mAtmInternal != null) { + mAtmInternal.setProfilerInfo(profilerInfo); + } + } + + ProfilerInfo getProfilerInfo() { + return mProfilerInfo; + } + } + final ProfileData mProfileData = new ProfileData(); /** * Stores a map of process name -> agent string. When a process is started and mAgentAppMap @@ -2225,8 +2262,7 @@ public class ActivityManagerService extends IActivityManager.Stub mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler); mActivityTaskManager = atm; - mActivityTaskManager.setActivityManagerService(this, mHandlerThread.getLooper(), - mIntentFirewall, mPendingIntentController); + mActivityTaskManager.setActivityManagerService(mIntentFirewall, mPendingIntentController); mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mProcessCpuThread = new Thread("CpuTracker") { @@ -3129,7 +3165,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - if (mProfileProc == app) { + if (mProfileData.getProfileProc() == app) { clearProfilerLocked(); } @@ -4410,16 +4446,18 @@ public class ActivityManagerService extends IActivityManager.Stub ProfilerInfo profilerInfo = null; String preBindAgent = null; - if (mProfileApp != null && mProfileApp.equals(processName)) { - mProfileProc = app; - if (mProfilerInfo != null) { + if (mProfileData.getProfileApp() != null + && mProfileData.getProfileApp().equals(processName)) { + mProfileData.setProfileProc(app); + if (mProfileData.getProfilerInfo() != null) { // Send a profiler info object to the app if either a file is given, or // an agent should be loaded at bind-time. - boolean needsInfo = mProfilerInfo.profileFile != null - || mProfilerInfo.attachAgentDuringBind; - profilerInfo = needsInfo ? new ProfilerInfo(mProfilerInfo) : null; - if (mProfilerInfo.agent != null) { - preBindAgent = mProfilerInfo.agent; + boolean needsInfo = mProfileData.getProfilerInfo().profileFile != null + || mProfileData.getProfilerInfo().attachAgentDuringBind; + profilerInfo = needsInfo + ? new ProfilerInfo(mProfileData.getProfilerInfo()) : null; + if (mProfileData.getProfilerInfo().agent != null) { + preBindAgent = mProfileData.getProfilerInfo().agent; } } } else if (instr != null && instr.mProfileFile != null) { @@ -4443,7 +4481,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (profilerInfo != null && profilerInfo.profileFd != null) { profilerInfo.profileFd = profilerInfo.profileFd.dup(); - if (TextUtils.equals(mProfileApp, processName) && mProfilerInfo != null) { + if (TextUtils.equals(mProfileData.getProfileApp(), processName) + && mProfileData.getProfilerInfo() != null) { clearProfilerLocked(); } } @@ -7444,17 +7483,17 @@ public class ActivityManagerService extends IActivityManager.Stub throw new SecurityException("Process not debuggable: " + app.packageName); } } - mProfileApp = processName; + mProfileData.setProfileApp(processName); - if (mProfilerInfo != null) { - if (mProfilerInfo.profileFd != null) { + if (mProfileData.getProfilerInfo() != null) { + if (mProfileData.getProfilerInfo().profileFd != null) { try { - mProfilerInfo.profileFd.close(); + mProfileData.getProfilerInfo().profileFd.close(); } catch (IOException e) { } } } - mProfilerInfo = new ProfilerInfo(profilerInfo); + mProfileData.setProfilerInfo(new ProfilerInfo(profilerInfo)); mProfileType = 0; } } @@ -9971,20 +10010,25 @@ public class ActivityManagerService extends IActivityManager.Stub pw.println(" mTrackAllocationApp=" + mTrackAllocationApp); } } - if (mProfileApp != null || mProfileProc != null || (mProfilerInfo != null && - (mProfilerInfo.profileFile != null || mProfilerInfo.profileFd != null))) { - if (dumpPackage == null || dumpPackage.equals(mProfileApp)) { + if (mProfileData.getProfileApp() != null || mProfileData.getProfileProc() != null + || (mProfileData.getProfilerInfo() != null && + (mProfileData.getProfilerInfo().profileFile != null + || mProfileData.getProfilerInfo().profileFd != null))) { + if (dumpPackage == null || dumpPackage.equals(mProfileData.getProfileApp())) { if (needSep) { pw.println(); needSep = false; } - pw.println(" mProfileApp=" + mProfileApp + " mProfileProc=" + mProfileProc); - if (mProfilerInfo != null) { - pw.println(" mProfileFile=" + mProfilerInfo.profileFile + " mProfileFd=" + - mProfilerInfo.profileFd); - pw.println(" mSamplingInterval=" + mProfilerInfo.samplingInterval + - " mAutoStopProfiler=" + mProfilerInfo.autoStopProfiler + - " mStreamingOutput=" + mProfilerInfo.streamingOutput); + pw.println(" mProfileApp=" + mProfileData.getProfileApp() + + " mProfileProc=" + mProfileData.getProfileProc()); + if (mProfileData.getProfilerInfo() != null) { + pw.println(" mProfileFile=" + mProfileData.getProfilerInfo().profileFile + + " mProfileFd=" + mProfileData.getProfilerInfo().profileFd); + pw.println(" mSamplingInterval=" + + mProfileData.getProfilerInfo().samplingInterval + + " mAutoStopProfiler=" + + mProfileData.getProfilerInfo().autoStopProfiler + + " mStreamingOutput=" + mProfileData.getProfilerInfo().streamingOutput); pw.println(" mProfileType=" + mProfileType); } } @@ -10264,19 +10308,26 @@ public class ActivityManagerService extends IActivityManager.Stub if (mTrackAllocationApp != null) { if (dumpPackage == null || dumpPackage.equals(mTrackAllocationApp)) { - proto.write(ActivityManagerServiceDumpProcessesProto.TRACK_ALLOCATION_APP, mTrackAllocationApp); + proto.write(ActivityManagerServiceDumpProcessesProto.TRACK_ALLOCATION_APP, + mTrackAllocationApp); } } - if (mProfileApp != null || mProfileProc != null || (mProfilerInfo != null && - (mProfilerInfo.profileFile != null || mProfilerInfo.profileFd != null))) { - if (dumpPackage == null || dumpPackage.equals(mProfileApp)) { + if (mProfileData.getProfileApp() != null || mProfileData.getProfileProc() != null + || (mProfileData.getProfilerInfo() != null && + (mProfileData.getProfilerInfo().profileFile != null + || mProfileData.getProfilerInfo().profileFd != null))) { + if (dumpPackage == null || dumpPackage.equals(mProfileData.getProfileApp())) { final long token = proto.start(ActivityManagerServiceDumpProcessesProto.PROFILE); - proto.write(ActivityManagerServiceDumpProcessesProto.Profile.APP_NAME, mProfileApp); - mProfileProc.writeToProto(proto,ActivityManagerServiceDumpProcessesProto.Profile.PROC); - if (mProfilerInfo != null) { - mProfilerInfo.writeToProto(proto, ActivityManagerServiceDumpProcessesProto.Profile.INFO); - proto.write(ActivityManagerServiceDumpProcessesProto.Profile.TYPE, mProfileType); + proto.write(ActivityManagerServiceDumpProcessesProto.Profile.APP_NAME, + mProfileData.getProfileApp()); + mProfileData.getProfileProc().writeToProto(proto, + ActivityManagerServiceDumpProcessesProto.Profile.PROC); + if (mProfileData.getProfilerInfo() != null) { + mProfileData.getProfilerInfo().writeToProto(proto, + ActivityManagerServiceDumpProcessesProto.Profile.INFO); + proto.write(ActivityManagerServiceDumpProcessesProto.Profile.TYPE, + mProfileType); } proto.end(token); } @@ -18033,8 +18084,8 @@ public class ActivityManagerService extends IActivityManager.Stub } private void stopProfilerLocked(ProcessRecord proc, int profileType) { - if (proc == null || proc == mProfileProc) { - proc = mProfileProc; + if (proc == null || proc == mProfileData.getProfileProc()) { + proc = mProfileData.getProfileProc(); profileType = mProfileType; clearProfilerLocked(); } @@ -18049,15 +18100,16 @@ public class ActivityManagerService extends IActivityManager.Stub } void clearProfilerLocked() { - if (mProfilerInfo !=null && mProfilerInfo.profileFd != null) { + if (mProfileData.getProfilerInfo() != null + && mProfileData.getProfilerInfo().profileFd != null) { try { - mProfilerInfo.profileFd.close(); + mProfileData.getProfilerInfo().profileFd.close(); } catch (IOException e) { } } - mProfileApp = null; - mProfileProc = null; - mProfilerInfo = null; + mProfileData.setProfileApp(null); + mProfileData.setProfileProc(null); + mProfileData.setProfilerInfo(null); } public boolean profileControl(String process, int userId, boolean start, @@ -18089,7 +18141,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (start) { stopProfilerLocked(null, 0); setProfileApp(proc.info, proc.processName, profilerInfo); - mProfileProc = proc; + mProfileData.setProfileProc(proc); mProfileType = profileType; ParcelFileDescriptor fd = profilerInfo.profileFd; try { @@ -18101,10 +18153,10 @@ public class ActivityManagerService extends IActivityManager.Stub proc.thread.profilerControl(start, profilerInfo, profileType); fd = null; try { - mProfilerInfo.profileFd.close(); + mProfileData.getProfilerInfo().profileFd.close(); } catch (IOException e) { } - mProfilerInfo.profileFd = null; + mProfileData.getProfilerInfo().profileFd = null; if (proc.pid == MY_PID) { // When profiling the system server itself, avoid closing the file diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index bb87ad031ad5..8a3f139858c8 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -1123,8 +1123,9 @@ final class ProcessRecord implements WindowProcessListener { @Override public void clearProfilerIfNeeded() { synchronized (mService) { - if (mService.mProfileProc == null || mService.mProfilerInfo == null - || mService.mProfileProc != this) { + if (mService.mProfileData.getProfileProc() == null + || mService.mProfileData.getProfilerInfo() == null + || mService.mProfileData.getProfileProc() != this) { return; } mService.clearProfilerLocked(); @@ -1198,32 +1199,15 @@ final class ProcessRecord implements WindowProcessListener { } @Override - public ProfilerInfo onStartActivity(int topProcessState) { + public void onStartActivity(int topProcessState, boolean setProfileProc) { synchronized (mService) { - ProfilerInfo profilerInfo = null; - if (mService.mProfileApp != null && mService.mProfileApp.equals(processName)) { - if (mService.mProfileProc == null || mService.mProfileProc == this) { - mService.mProfileProc = this; - final ProfilerInfo profilerInfoSvc = mService.mProfilerInfo; - if (profilerInfoSvc != null && profilerInfoSvc.profileFile != null) { - if (profilerInfoSvc.profileFd != null) { - try { - profilerInfoSvc.profileFd = profilerInfoSvc.profileFd.dup(); - } catch (IOException e) { - profilerInfoSvc.closeFd(); - } - } - - profilerInfo = new ProfilerInfo(profilerInfoSvc); - } - } + if (setProfileProc) { + mService.mProfileData.setProfileProc(this); } hasShownUi = true; setPendingUiClean(true); forceProcessStateUpTo(topProcessState); - - return profilerInfo; } } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index a8b4a9d43ebb..341a777e6d45 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -2679,136 +2679,129 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai || (lastFocusedStack.mLastPausedActivity != null && !lastFocusedStack.mLastPausedActivity.fullscreen)); - // The contained logic must be synchronized, since we are both changing the visibility - // and updating the {@link Configuration}. {@link ActivityRecord#setVisibility} will - // ultimately cause the client code to schedule a layout. Since layouts retrieve the - // current {@link Configuration}, we must ensure that the below code updates it before - // the layout can occur. - synchronized(mWindowManager.getWindowManagerLock()) { - // This activity is now becoming visible. - if (!next.visible || next.stopped || lastActivityTranslucent) { - next.setVisibility(true); + // This activity is now becoming visible. + if (!next.visible || next.stopped || lastActivityTranslucent) { + next.setVisibility(true); + } + + // schedule launch ticks to collect information about slow apps. + next.startLaunchTickingLocked(); + + ActivityRecord lastResumedActivity = + lastFocusedStack == null ? null : lastFocusedStack.mResumedActivity; + final ActivityState lastState = next.getState(); + + mService.updateCpuStats(); + + if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next + + " (in existing)"); + + next.setState(RESUMED, "resumeTopActivityInnerLocked"); + + next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, + true /* updateLru */, true /* activityChange */, true /* updateOomAdj */); + updateLRUListLocked(next); + + // Have the window manager re-evaluate the orientation of + // the screen based on the new activity order. + boolean notUpdated = true; + + if (isFocusedStackOnDisplay()) { + // We have special rotation behavior when here is some active activity that + // requests specific orientation or Keyguard is locked. Make sure all activity + // visibilities are set correctly as well as the transition is updated if needed + // to get the correct rotation behavior. Otherwise the following call to update + // the orientation may cause incorrect configurations delivered to client as a + // result of invisible window resize. + // TODO: Remove this once visibilities are set correctly immediately when + // starting an activity. + notUpdated = !mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId, + true /* markFrozenIfConfigChanged */, false /* deferResume */); + } + + if (notUpdated) { + // The configuration update wasn't able to keep the existing + // instance of the activity, and instead started a new one. + // We should be all done, but let's just make sure our activity + // is still at the top and schedule another run if something + // weird happened. + ActivityRecord nextNext = topRunningActivityLocked(); + if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES, + "Activity config changed during resume: " + next + + ", new next: " + nextNext); + if (nextNext != next) { + // Do over! + mStackSupervisor.scheduleResumeTopActivities(); } - - // schedule launch ticks to collect information about slow apps. - next.startLaunchTickingLocked(); - - ActivityRecord lastResumedActivity = - lastFocusedStack == null ? null : lastFocusedStack.mResumedActivity; - final ActivityState lastState = next.getState(); - - mService.updateCpuStats(); - - if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + next - + " (in existing)"); - - next.setState(RESUMED, "resumeTopActivityInnerLocked"); - - next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, - true /* updateLru */, true /* activityChange */, true /* updateOomAdj */); - updateLRUListLocked(next); - - // Have the window manager re-evaluate the orientation of - // the screen based on the new activity order. - boolean notUpdated = true; - - if (isFocusedStackOnDisplay()) { - // We have special rotation behavior when here is some active activity that - // requests specific orientation or Keyguard is locked. Make sure all activity - // visibilities are set correctly as well as the transition is updated if needed - // to get the correct rotation behavior. Otherwise the following call to update - // the orientation may cause incorrect configurations delivered to client as a - // result of invisible window resize. - // TODO: Remove this once visibilities are set correctly immediately when - // starting an activity. - notUpdated = !mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId, - true /* markFrozenIfConfigChanged */, false /* deferResume */); + if (!next.visible || next.stopped) { + next.setVisibility(true); } + next.completeResumeLocked(); + if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); + return true; + } - if (notUpdated) { - // The configuration update wasn't able to keep the existing - // instance of the activity, and instead started a new one. - // We should be all done, but let's just make sure our activity - // is still at the top and schedule another run if something - // weird happened. - ActivityRecord nextNext = topRunningActivityLocked(); - if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES, - "Activity config changed during resume: " + next - + ", new next: " + nextNext); - if (nextNext != next) { - // Do over! - mStackSupervisor.scheduleResumeTopActivities(); - } - if (!next.visible || next.stopped) { - next.setVisibility(true); + try { + final ClientTransaction transaction = + ClientTransaction.obtain(next.app.getThread(), next.appToken); + // Deliver all pending results. + ArrayList<ResultInfo> a = next.results; + if (a != null) { + final int N = a.size(); + if (!next.finishing && N > 0) { + if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, + "Delivering results to " + next + ": " + a); + transaction.addCallback(ActivityResultItem.obtain(a)); } - next.completeResumeLocked(); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); - return true; } - try { - final ClientTransaction transaction = - ClientTransaction.obtain(next.app.getThread(), next.appToken); - // Deliver all pending results. - ArrayList<ResultInfo> a = next.results; - if (a != null) { - final int N = a.size(); - if (!next.finishing && N > 0) { - if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, - "Delivering results to " + next + ": " + a); - transaction.addCallback(ActivityResultItem.obtain(a)); - } - } - - if (next.newIntents != null) { - transaction.addCallback(NewIntentItem.obtain(next.newIntents, - false /* andPause */)); - } + if (next.newIntents != null) { + transaction.addCallback(NewIntentItem.obtain(next.newIntents, + false /* andPause */)); + } - // Well the app will no longer be stopped. - // Clear app token stopped state in window manager if needed. - next.notifyAppResumed(next.stopped); - - EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId, - System.identityHashCode(next), next.getTask().taskId, - next.shortComponentName); - - next.sleeping = false; - mService.getAppWarningsLocked().onResumeActivity(next); - next.app.setPendingUiCleanAndForceProcessStateUpTo(mService.mTopProcessState); - next.clearOptionsLocked(); - transaction.setLifecycleStateRequest( - ResumeActivityItem.obtain(next.app.getReportedProcState(), - getDisplay().getWindowContainerController() - .isNextTransitionForward())); - mService.getLifecycleManager().scheduleTransaction(transaction); - - if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " - + next); - } catch (Exception e) { - // Whoops, need to restart this activity! - if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to " - + lastState + ": " + next); - next.setState(lastState, "resumeTopActivityInnerLocked"); - - // lastResumedActivity being non-null implies there is a lastStack present. - if (lastResumedActivity != null) { - lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked"); - } + // Well the app will no longer be stopped. + // Clear app token stopped state in window manager if needed. + next.notifyAppResumed(next.stopped); + + EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId, + System.identityHashCode(next), next.getTask().taskId, + next.shortComponentName); + + next.sleeping = false; + mService.getAppWarningsLocked().onResumeActivity(next); + next.app.setPendingUiCleanAndForceProcessStateUpTo(mService.mTopProcessState); + next.clearOptionsLocked(); + transaction.setLifecycleStateRequest( + ResumeActivityItem.obtain(next.app.getReportedProcState(), + getDisplay().getWindowContainerController() + .isNextTransitionForward())); + mService.getLifecycleManager().scheduleTransaction(transaction); + + if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " + + next); + } catch (Exception e) { + // Whoops, need to restart this activity! + if (DEBUG_STATES) Slog.v(TAG_STATES, "Resume failed; resetting state to " + + lastState + ": " + next); + next.setState(lastState, "resumeTopActivityInnerLocked"); + + // lastResumedActivity being non-null implies there is a lastStack present. + if (lastResumedActivity != null) { + lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked"); + } - Slog.i(TAG, "Restarting because process died: " + next); - if (!next.hasBeenLaunched) { - next.hasBeenLaunched = true; - } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedStack != null - && lastFocusedStack.isTopStackOnDisplay()) { - next.showStartingWindow(null /* prev */, false /* newTask */, - false /* taskSwitch */); - } - mStackSupervisor.startSpecificActivityLocked(next, true, false); - if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); - return true; + Slog.i(TAG, "Restarting because process died: " + next); + if (!next.hasBeenLaunched) { + next.hasBeenLaunched = true; + } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedStack != null + && lastFocusedStack.isTopStackOnDisplay()) { + next.showStartingWindow(null /* prev */, false /* newTask */, + false /* taskSwitch */); } + mStackSupervisor.startSpecificActivityLocked(next, true, false); + if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); + return true; } // From this point on, if something goes wrong there is no way @@ -4841,35 +4834,33 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai mTmpBounds.clear(); mTmpInsetBounds.clear(); - synchronized (mWindowManager.getWindowManagerLock()) { - for (int i = mTaskHistory.size() - 1; i >= 0; i--) { - final TaskRecord task = mTaskHistory.get(i); - if (task.isResizeable()) { - if (inFreeformWindowingMode()) { - // TODO(b/71028874): Can be removed since each freeform task is its own - // stack. - // For freeform stack we don't adjust the size of the tasks to match that - // of the stack, but we do try to make sure the tasks are still contained - // with the bounds of the stack. - if (task.getOverrideBounds() != null) { - mTmpRect2.set(task.getOverrideBounds()); - fitWithinBounds(mTmpRect2, bounds); - task.updateOverrideConfiguration(mTmpRect2); - } - } else { - task.updateOverrideConfiguration(taskBounds, insetBounds); + for (int i = mTaskHistory.size() - 1; i >= 0; i--) { + final TaskRecord task = mTaskHistory.get(i); + if (task.isResizeable()) { + if (inFreeformWindowingMode()) { + // TODO(b/71028874): Can be removed since each freeform task is its own + // stack. + // For freeform stack we don't adjust the size of the tasks to match that + // of the stack, but we do try to make sure the tasks are still contained + // with the bounds of the stack. + if (task.getOverrideBounds() != null) { + mTmpRect2.set(task.getOverrideBounds()); + fitWithinBounds(mTmpRect2, bounds); + task.updateOverrideConfiguration(mTmpRect2); } - } - - mTmpBounds.put(task.taskId, task.getOverrideBounds()); - if (tempTaskInsetBounds != null) { - mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds); + } else { + task.updateOverrideConfiguration(taskBounds, insetBounds); } } - mWindowContainerController.resize(bounds, mTmpBounds, mTmpInsetBounds); - setBounds(bounds); + mTmpBounds.put(task.taskId, task.getOverrideBounds()); + if (tempTaskInsetBounds != null) { + mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds); + } } + + mWindowContainerController.resize(bounds, mTmpBounds, mTmpInsetBounds); + setBounds(bounds); } void onPipAnimationEndResize() { diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 9bcee8a3ab23..76278d826b97 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -2051,7 +2051,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - mService.mAmInternal.trimApplications(); + mService.mH.post(() -> mService.mAmInternal.trimApplications()); //dump(); //mWindowManager.dump(); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index dcc7bc577396..d6655928105e 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -22,6 +22,7 @@ import android.annotation.UserIdInt; import android.app.AppProtoEnums; import android.app.IActivityManager; import android.app.IApplicationThread; +import android.app.ProfilerInfo; import android.content.ComponentName; import android.content.IIntentSender; import android.content.Intent; @@ -468,4 +469,8 @@ public abstract class ActivityTaskManagerInternal { public abstract void clearLockedTasks(String reason); public abstract void updateUserConfiguration(); public abstract boolean canShowErrorDialogs(); + + public abstract void setProfileApp(String profileApp); + public abstract void setProfileProc(WindowProcessController wpc); + public abstract void setProfilerInfo(ProfilerInfo profilerInfo); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 3359eac880c7..faf9531f8f2a 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -190,7 +190,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.IUserManager; import android.os.LocaleList; -import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.PowerManager; @@ -247,9 +246,11 @@ import com.android.internal.util.Preconditions; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.AppOpsService; import com.android.server.AttributeCache; +import com.android.server.DisplayThread; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemServiceManager; +import com.android.server.UiThread; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService; import com.android.server.am.ActivityManagerServiceDumpActivitiesProto; @@ -347,7 +348,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { IntentFirewall mIntentFirewall; /* Global service lock used by the package the owns this service. */ - Object mGlobalLock; + final WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock(); ActivityStackSupervisor mStackSupervisor; WindowManagerService mWindowManager; private UserManagerService mUserManager; @@ -466,6 +467,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { String mTopAction = Intent.ACTION_MAIN; String mTopData; + /** Profiling app information. */ + String mProfileApp = null; + WindowProcessController mProfileProc = null; + ProfilerInfo mProfilerInfo = null; + /** * Dump of the activity state at the time of the last ANR. Cleared after * {@link WindowManagerService#LAST_ANR_LIFETIME_DURATION_MSECS} @@ -716,11 +722,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } - // TODO: Will be converted to WM lock once transition is complete. - public void setActivityManagerService(Object globalLock, Looper looper, - IntentFirewall intentFirewall, PendingIntentController intentController) { - mGlobalLock = globalLock; - mH = new H(looper); + public WindowManagerGlobalLock getGlobalLock() { + return mGlobalLock; + } + + public void setActivityManagerService(IntentFirewall intentFirewall, + PendingIntentController intentController) { + mH = new H(); mUiHandler = new UiHandler(); mIntentFirewall = intentFirewall; final File systemDir = SystemServiceManager.ensureSystemDir(); @@ -5487,8 +5495,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_SUPERVISOR_STACK_MSG = 200; - public H(Looper looper) { - super(looper, null, true); + public H() { + super(DisplayThread.get().getLooper()); } @Override @@ -5506,7 +5514,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { static final int DISMISS_DIALOG_UI_MSG = 1; public UiHandler() { - super(com.android.server.UiThread.get().getLooper(), null, true); + super(UiThread.get().getLooper(), null, true); } @Override @@ -6762,5 +6770,26 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { && mAmInternal.getCurrentUser().isDemo()); } } + + @Override + public void setProfileApp(String profileApp) { + synchronized (mGlobalLock) { + mProfileApp = profileApp; + } + } + + @Override + public void setProfileProc(WindowProcessController wpc) { + synchronized (mGlobalLock) { + mProfileProc = wpc; + } + } + + @Override + public void setProfilerInfo(ProfilerInfo profilerInfo) { + synchronized (mGlobalLock) { + mProfilerInfo = profilerInfo; + } + } } } diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 9aeb0253250a..067b01a1b6ad 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -42,7 +42,6 @@ import android.os.Trace; import android.util.Slog; import android.view.IRecentsAnimationRunner; -import com.android.server.wm.AssistDataReceiverProxy; import com.android.server.am.AssistDataRequester; import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; @@ -124,7 +123,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent); - mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true); + mService.mH.post(() -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true)); mWindowManager.deferSurfaceLayout(); try { @@ -234,7 +233,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks, mStackSupervisor.sendPowerHintForLaunchEndIfNeeded(); } - mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false); + mService.mH.post( + () -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, false)); mWindowManager.inSurfaceTransaction(() -> { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a641f75221d3..56d96aa134c4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -441,7 +441,7 @@ public class WindowManagerService extends IWindowManager.Stub final WindowHashMap mWindowMap = new WindowHashMap(); /** Global service lock used by the package the owns this service. */ - WindowManagerGlobalLock mGlobalLock = new WindowManagerGlobalLock(); + final WindowManagerGlobalLock mGlobalLock; /** * List of app window tokens that are waiting for replacing windows. If the @@ -855,9 +855,11 @@ public class WindowManagerService extends IWindowManager.Stub } public static WindowManagerService main(final Context context, final InputManagerService im, - final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy) { + final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy, + final WindowManagerGlobalLock globalLock) { DisplayThread.getHandler().runWithScissors(() -> - sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy), + sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy, + globalLock), 0); return sInstance; } @@ -879,8 +881,10 @@ public class WindowManagerService extends IWindowManager.Stub } private WindowManagerService(Context context, InputManagerService inputManager, - boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy) { + boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy, + WindowManagerGlobalLock globalLock) { installLock(this, INDEX_WINDOW); + mGlobalLock = globalLock; mContext = context; mAllowBootMessages = showBootMsgs; mOnlyCore = onlyCore; @@ -2629,21 +2633,16 @@ public class WindowManagerService extends IWindowManager.Stub /** * Starts deferring layout passes. Useful when doing multiple changes but to optimize * performance, only one layout pass should be done. This can be called multiple times, and - * layouting will be resumed once the last caller has called {@link #continueSurfaceLayout} + * layouting will be resumed once the last caller has called + * {@link #continueSurfaceLayout}. */ - public void deferSurfaceLayout() { - synchronized (mGlobalLock) { - mWindowPlacerLocked.deferLayout(); - } + void deferSurfaceLayout() { + mWindowPlacerLocked.deferLayout(); } - /** - * Resumes layout passes after deferring them. See {@link #deferSurfaceLayout()} - */ - public void continueSurfaceLayout() { - synchronized (mGlobalLock) { - mWindowPlacerLocked.continueLayout(); - } + /** Resumes layout passes after deferring them. See {@link #deferSurfaceLayout()} */ + void continueSurfaceLayout() { + mWindowPlacerLocked.continueLayout(); } /** @@ -6902,7 +6901,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_DISPLAY) { Slog.d(TAG, "setVr2dDisplayId called for: " + vr2dDisplayId); } - synchronized (WindowManagerService.this) { + synchronized (mGlobalLock) { mVr2dDisplayId = vr2dDisplayId; } } @@ -7027,10 +7026,6 @@ public class WindowManagerService extends IWindowManager.Stub * WARNING: This interrupts surface updates, be careful! Don't * execute within the transaction for longer than you would * execute on an animation thread. - * WARNING: This holds the WindowManager lock, so if exec will acquire - * the ActivityManager lock, you should hold it BEFORE calling this - * otherwise there is a risk of deadlock if another thread holding the AM - * lock waits on the WM lock. * WARNING: This method contains locks known to the State of California * to cause Deadlocks and other conditions. * @@ -7051,19 +7046,12 @@ public class WindowManagerService extends IWindowManager.Stub * deferSurfaceLayout may be a little too broad, in particular the total * enclosure of startActivityUnchecked which could run for quite some time. */ - public void inSurfaceTransaction(Runnable exec) { - // We hold the WindowManger lock to ensure relayoutWindow - // does not return while a Surface transaction is opening. - // The client depends on us to have resized the surface - // by that point (b/36462635) - - synchronized (mGlobalLock) { - SurfaceControl.openTransaction(); - try { - exec.run(); - } finally { - SurfaceControl.closeTransaction(); - } + void inSurfaceTransaction(Runnable exec) { + SurfaceControl.openTransaction(); + try { + exec.run(); + } finally { + SurfaceControl.closeTransaction(); } } diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index bb1725477ac0..4c9788db7c3c 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -56,6 +56,7 @@ import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.Watchdog; +import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; @@ -690,24 +691,52 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } void addPackage(String pkg, long versionCode) { - // TODO(b/80414790): Calling directly into AM for now which can lead to deadlock once we are - // using WM lock. Need to figure-out if it is okay to do this asynchronously. if (mListener == null) return; - mListener.addPackage(pkg, versionCode); + // Posting on handler so WM lock isn't held when we call into AM. + final Message m = PooledLambda.obtainMessage( + WindowProcessListener::addPackage, mListener, pkg, versionCode); + mAtm.mH.sendMessage(m); } ProfilerInfo onStartActivity(int topProcessState) { - // TODO(b/80414790): Calling directly into AM for now which can lead to deadlock once we are - // using WM lock. Need to figure-out if it is okay to do this asynchronously. - if (mListener == null) return null; - return mListener.onStartActivity(topProcessState); + ProfilerInfo profilerInfo = null; + boolean setProfileProc = false; + if (mAtm.mProfileApp != null + && mAtm.mProfileApp.equals(mName)) { + if (mAtm.mProfileProc == null || mAtm.mProfileProc == this) { + setProfileProc = true; + final ProfilerInfo profilerInfoSvc = mAtm.mProfilerInfo; + if (profilerInfoSvc != null && profilerInfoSvc.profileFile != null) { + if (profilerInfoSvc.profileFd != null) { + try { + profilerInfoSvc.profileFd = profilerInfoSvc.profileFd.dup(); + } catch (IOException e) { + profilerInfoSvc.closeFd(); + } + } + + profilerInfo = new ProfilerInfo(profilerInfoSvc); + } + } + } + + + if (mListener != null) { + // Posting on handler so WM lock isn't held when we call into AM. + final Message m = PooledLambda.obtainMessage(WindowProcessListener::onStartActivity, + mListener, topProcessState, setProfileProc); + mAtm.mH.sendMessage(m); + } + + return profilerInfo; } public void appDied() { - // TODO(b/80414790): Calling directly into AM for now which can lead to deadlock once we are - // using WM lock. Need to figure-out if it is okay to do this asynchronously. if (mListener == null) return; - mListener.appDied(); + // Posting on handler so WM lock isn't held when we call into AM. + final Message m = PooledLambda.obtainMessage( + WindowProcessListener::appDied, mListener); + mAtm.mH.sendMessage(m); } void registerDisplayConfigurationListenerLocked(ActivityDisplay activityDisplay) { diff --git a/services/core/java/com/android/server/wm/WindowProcessListener.java b/services/core/java/com/android/server/wm/WindowProcessListener.java index 7f20f4b0add9..bce5e2dfeb44 100644 --- a/services/core/java/com/android/server/wm/WindowProcessListener.java +++ b/services/core/java/com/android/server/wm/WindowProcessListener.java @@ -16,7 +16,6 @@ package com.android.server.wm; -import android.app.ProfilerInfo; import android.util.proto.ProtoOutputStream; /** @@ -58,7 +57,7 @@ public interface WindowProcessListener { void addPackage(String pkg, long versionCode); /** Called when we are in the process on starting an activity. */ - ProfilerInfo onStartActivity(int topProcessState); + void onStartActivity(int topProcessState, boolean setProfileProc); /** App died :(...oh well */ void appDied(); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 54a140dec713..88111ac7354b 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -134,6 +134,7 @@ import com.android.server.usage.UsageStatsService; import com.android.server.vr.VrManagerService; import com.android.server.webkit.WebViewUpdateService; import com.android.server.wm.ActivityTaskManagerService; +import com.android.server.wm.WindowManagerGlobalLock; import com.android.server.wm.WindowManagerService; import dalvik.system.VMRuntime; @@ -275,6 +276,7 @@ public final class SystemServer { // TODO: remove all of these references by improving dependency resolution and boot phases private PowerManagerService mPowerManagerService; private ActivityManagerService mActivityManagerService; + private WindowManagerGlobalLock mWindowManagerGlobalLock; private WebViewUpdateService mWebViewUpdateService; private DisplayManagerService mDisplayManagerService; private PackageManagerService mPackageManagerService; @@ -597,6 +599,7 @@ public final class SystemServer { mSystemServiceManager, atm); mActivityManagerService.setSystemServiceManager(mSystemServiceManager); mActivityManagerService.setInstaller(installer); + mWindowManagerGlobalLock = atm.getGlobalLock(); traceEnd(); // Power manager needs to be started early because other services need it. @@ -921,7 +924,7 @@ public final class SystemServer { ConcurrentUtils.waitForFutureNoInterrupt(mSensorServiceStart, START_SENSOR_SERVICE); mSensorServiceStart = null; wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore, - new PhoneWindowManager()); + new PhoneWindowManager(), mWindowManagerGlobalLock); ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO); ServiceManager.addService(Context.INPUT_SERVICE, inputManager, diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java index 4e75ec9e8348..9a13efb4c58b 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java @@ -124,9 +124,10 @@ public class WindowManagerServiceRule implements TestRule { doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt()); } - mService = WindowManagerService.main(context, ims, false, - false, mPolicy = new TestWindowManagerPolicy( - WindowManagerServiceRule.this::getWindowManagerService)); + mService = WindowManagerService.main(context, ims, false, false, + mPolicy = new TestWindowManagerPolicy( + WindowManagerServiceRule.this::getWindowManagerService), + new WindowManagerGlobalLock()); mService.mTransactionFactory = () -> { final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); mSurfaceTransactions.add(new WeakReference<>(transaction)); diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java index 9e12f020d06e..b318b9190249 100644 --- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java @@ -53,14 +53,6 @@ import org.mockito.invocation.InvocationOnMock; public class WindowTestUtils { private static int sNextTaskId = 0; - /** Retrieves an instance of a mock {@link WindowManagerService}. */ - static WindowManagerService getMockWindowManagerService() { - final WindowManagerService service = mock(WindowManagerService.class); - final WindowManagerGlobalLock lock = new WindowManagerGlobalLock(); - doReturn(lock).when(service).getWindowManagerLock(); - return service; - } - /** An extension of {@link DisplayContent} to gain package scoped access. */ public static class TestDisplayContent extends DisplayContent { diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 9d28c5754040..c35e4d6766a9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -153,8 +153,7 @@ class ActivityTestsBase { void setupActivityManagerService( TestActivityManagerService am, TestActivityTaskManagerService atm) { - atm.setActivityManagerService(am, am.mHandlerThread.getLooper(), am.mIntentFirewall, - am.mPendingIntentController); + atm.setActivityManagerService(am.mIntentFirewall, am.mPendingIntentController); atm.mAmInternal = am.getLocalService(); am.mAtmInternal = atm.getLocalService(); // Makes sure the supervisor is using with the spy object. @@ -629,7 +628,7 @@ class ActivityTestsBase { } private static WindowManagerService prepareMockWindowManager() { - final WindowManagerService service = WindowTestUtils.getMockWindowManagerService(); + final WindowManagerService service = mock(WindowManagerService.class); doAnswer((InvocationOnMock invocationOnMock) -> { final Runnable runnable = invocationOnMock.<Runnable>getArgument(0); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 115bcb1f44a2..3b4ab3839146 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -38,15 +38,6 @@ import org.mockito.invocation.InvocationOnMock; * to WindowManager related test functionality. */ public class WindowTestUtils { - private static int sNextTaskId = 0; - - /** Retrieves an instance of a mock {@link WindowManagerService}. */ - static WindowManagerService getMockWindowManagerService() { - final WindowManagerService service = mock(WindowManagerService.class); - final WindowManagerGlobalLock lock = new WindowManagerGlobalLock(); - doReturn(lock).when(service).getWindowManagerLock(); - return service; - } /** An extension of {@link DisplayContent} to gain package scoped access. */ public static class TestDisplayContent extends DisplayContent { |