OSDN Git Service

Do not retry taking screenshots
authorJorim Jaggi <jjaggi@google.com>
Thu, 7 Apr 2016 23:27:17 +0000 (16:27 -0700)
committerJorim Jaggi <jjaggi@google.com>
Sat, 9 Apr 2016 01:13:29 +0000 (01:13 +0000)
We are holding the activity manager lock during a sleep() :-(, which
is a really really bad idea, and leads to delays in certain cases.

Bug: 28026841
Change-Id: I0855350ee429907e4597e5813c7e4fefd889319d

services/core/java/com/android/server/wm/WindowManagerService.java

index 27126e6..5c9d313 100644 (file)
@@ -6024,7 +6024,6 @@ public class WindowManagerService extends IWindowManager.Stub
             minLayer = Integer.MAX_VALUE;
         }
 
-        int retryCount = 0;
         WindowState appWin = null;
 
         boolean appIsImTarget;
@@ -6038,193 +6037,172 @@ public class WindowManagerService extends IWindowManager.Stub
         final int aboveAppLayer = (mPolicy.windowTypeToLayerLw(TYPE_APPLICATION) + 1)
                 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
 
-        while (true) {
-            if (retryCount++ > 0) {
-                // Reset max/min layers on retries so we don't accidentally take a screenshot of a
-                // layer based on the previous try.
-                maxLayer = 0;
-                minLayer = Integer.MAX_VALUE;
-                try {
-                    Thread.sleep(100);
-                } catch (InterruptedException e) {
+        synchronized(mWindowMap) {
+            // Figure out the part of the screen that is actually the app.
+            appWin = null;
+            final WindowList windows = displayContent.getWindowList();
+            for (int i = windows.size() - 1; i >= 0; i--) {
+                WindowState ws = windows.get(i);
+                if (!ws.mHasSurface) {
+                    continue;
                 }
-            }
-            synchronized(mWindowMap) {
-                // Figure out the part of the screen that is actually the app.
-                appWin = null;
-                final WindowList windows = displayContent.getWindowList();
-                for (int i = windows.size() - 1; i >= 0; i--) {
-                    WindowState ws = windows.get(i);
-                    if (!ws.mHasSurface) {
+                if (ws.mLayer >= aboveAppLayer) {
+                    continue;
+                }
+                if (ws.mIsImWindow) {
+                    if (!appIsImTarget) {
                         continue;
                     }
-                    if (ws.mLayer >= aboveAppLayer) {
+                } else if (ws.mIsWallpaper) {
+                    if (appWin == null) {
+                        // We have not ran across the target window yet, so it is probably
+                        // behind the wallpaper. This can happen when the keyguard is up and
+                        // all windows are moved behind the wallpaper. We don't want to
+                        // include the wallpaper layer in the screenshot as it will coverup
+                        // the layer of the target window.
                         continue;
                     }
-                    if (ws.mIsImWindow) {
-                        if (!appIsImTarget) {
-                            continue;
-                        }
-                    } else if (ws.mIsWallpaper) {
-                        if (appWin == null) {
-                            // We have not ran across the target window yet, so it is probably
-                            // behind the wallpaper. This can happen when the keyguard is up and
-                            // all windows are moved behind the wallpaper. We don't want to
-                            // include the wallpaper layer in the screenshot as it will coverup
-                            // the layer of the target window.
-                            continue;
-                        }
-                        // Fall through. The target window is in front of the wallpaper. For this
-                        // case we want to include the wallpaper layer in the screenshot because
-                        // the target window might have some transparent areas.
-                    } else if (appToken != null) {
-                        if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
-                            // This app window is of no interest if it is not associated with the
-                            // screenshot app.
-                            continue;
-                        }
-                        appWin = ws;
-                    }
-
-                    // Include this window.
-
-                    final WindowStateAnimator winAnim = ws.mWinAnimator;
-                    int layer = winAnim.mSurfaceController.getLayer();
-                    if (maxLayer < layer) {
-                        maxLayer = layer;
-                    }
-                    if (minLayer > layer) {
-                        minLayer = layer;
+                    // Fall through. The target window is in front of the wallpaper. For this
+                    // case we want to include the wallpaper layer in the screenshot because
+                    // the target window might have some transparent areas.
+                } else if (appToken != null) {
+                    if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
+                        // This app window is of no interest if it is not associated with the
+                        // screenshot app.
+                        continue;
                     }
+                    appWin = ws;
+                }
 
-                    // Don't include wallpaper in bounds calculation
-                    if (!includeFullDisplay && !ws.mIsWallpaper) {
-                        final Rect wf = ws.mFrame;
-                        final Rect cr = ws.mContentInsets;
-                        int left = wf.left + cr.left;
-                        int top = wf.top + cr.top;
-                        int right = wf.right - cr.right;
-                        int bottom = wf.bottom - cr.bottom;
-                        frame.union(left, top, right, bottom);
-                        ws.getVisibleBounds(stackBounds);
-                        if (!Rect.intersects(frame, stackBounds)) {
-                            // Set frame empty if there's no intersection.
-                            frame.setEmpty();
-                        }
-                    }
+                // Include this window.
 
-                    if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
-                            ws.isDisplayedLw() && winAnim.getShown()) {
-                        screenshotReady = true;
-                    }
+                final WindowStateAnimator winAnim = ws.mWinAnimator;
+                int layer = winAnim.mSurfaceController.getLayer();
+                if (maxLayer < layer) {
+                    maxLayer = layer;
+                }
+                if (minLayer > layer) {
+                    minLayer = layer;
+                }
 
-                    if (ws.isObscuringFullscreen(displayInfo)){
-                        break;
+                // Don't include wallpaper in bounds calculation
+                if (!includeFullDisplay && !ws.mIsWallpaper) {
+                    final Rect wf = ws.mFrame;
+                    final Rect cr = ws.mContentInsets;
+                    int left = wf.left + cr.left;
+                    int top = wf.top + cr.top;
+                    int right = wf.right - cr.right;
+                    int bottom = wf.bottom - cr.bottom;
+                    frame.union(left, top, right, bottom);
+                    ws.getVisibleBounds(stackBounds);
+                    if (!Rect.intersects(frame, stackBounds)) {
+                        // Set frame empty if there's no intersection.
+                        frame.setEmpty();
                     }
                 }
 
-                if (appToken != null && appWin == null) {
-                    // Can't find a window to snapshot.
-                    if (DEBUG_SCREENSHOT) Slog.i(TAG_WM,
-                            "Screenshot: Couldn't find a surface matching " + appToken);
-                    return null;
+                if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
+                        ws.isDisplayedLw() && winAnim.getShown()) {
+                    screenshotReady = true;
                 }
 
-                if (!screenshotReady) {
-                    if (retryCount > MAX_SCREENSHOT_RETRIES) {
-                        Slog.i(TAG_WM, "Screenshot max retries " + retryCount + " of " + appToken +
-                                " appWin=" + (appWin == null ? "null" : (appWin + " drawState=" +
-                                appWin.mWinAnimator.mDrawState)));
-                        return null;
-                    }
-
-                    // Delay and hope that window gets drawn.
-                    if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot: No image ready for " + appToken
-                            + ", " + appWin + " drawState=" + appWin.mWinAnimator.mDrawState);
-                    continue;
+                if (ws.isObscuringFullscreen(displayInfo)){
+                    break;
                 }
+            }
 
-                // Screenshot is ready to be taken. Everything from here below will continue
-                // through the bottom of the loop and return a value. We only stay in the loop
-                // because we don't want to release the mWindowMap lock until the screenshot is
-                // taken.
+            if (appToken != null && appWin == null) {
+                // Can't find a window to snapshot.
+                if (DEBUG_SCREENSHOT) Slog.i(TAG_WM,
+                        "Screenshot: Couldn't find a surface matching " + appToken);
+                return null;
+            }
 
-                if (maxLayer == 0) {
-                    if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + appToken
-                            + ": returning null maxLayer=" + maxLayer);
-                    return null;
-                }
+            if (!screenshotReady) {
+                Slog.i(TAG_WM, "Failed to capture screenshot of " + appToken +
+                        " appWin=" + (appWin == null ? "null" : (appWin + " drawState=" +
+                        appWin.mWinAnimator.mDrawState)));
+                return null;
+            }
 
-                if (!includeFullDisplay) {
-                    // Constrain frame to the screen size.
-                    if (!frame.intersect(0, 0, dw, dh)) {
-                        frame.setEmpty();
-                    }
-                } else {
-                    // Caller just wants entire display.
-                    frame.set(0, 0, dw, dh);
-                }
-                if (frame.isEmpty()) {
-                    return null;
-                }
+            // Screenshot is ready to be taken. Everything from here below will continue
+            // through the bottom of the loop and return a value. We only stay in the loop
+            // because we don't want to release the mWindowMap lock until the screenshot is
+            // taken.
 
-                if (width < 0) {
-                    width = (int) (frame.width() * frameScale);
-                }
-                if (height < 0) {
-                    height = (int) (frame.height() * frameScale);
-                }
+            if (maxLayer == 0) {
+                if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + appToken
+                        + ": returning null maxLayer=" + maxLayer);
+                return null;
+            }
 
-                // Tell surface flinger what part of the image to crop. Take the top
-                // right part of the application, and crop the larger dimension to fit.
-                Rect crop = new Rect(frame);
-                if (width / (float) frame.width() < height / (float) frame.height()) {
-                    int cropWidth = (int)((float)width / (float)height * frame.height());
-                    crop.right = crop.left + cropWidth;
-                } else {
-                    int cropHeight = (int)((float)height / (float)width * frame.width());
-                    crop.bottom = crop.top + cropHeight;
+            if (!includeFullDisplay) {
+                // Constrain frame to the screen size.
+                if (!frame.intersect(0, 0, dw, dh)) {
+                    frame.setEmpty();
                 }
+            } else {
+                // Caller just wants entire display.
+                frame.set(0, 0, dw, dh);
+            }
+            if (frame.isEmpty()) {
+                return null;
+            }
 
-                // The screenshot API does not apply the current screen rotation.
-                int rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
+            if (width < 0) {
+                width = (int) (frame.width() * frameScale);
+            }
+            if (height < 0) {
+                height = (int) (frame.height() * frameScale);
+            }
 
-                if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
-                    rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
-                }
+            // Tell surface flinger what part of the image to crop. Take the top
+            // right part of the application, and crop the larger dimension to fit.
+            Rect crop = new Rect(frame);
+            if (width / (float) frame.width() < height / (float) frame.height()) {
+                int cropWidth = (int)((float)width / (float)height * frame.height());
+                crop.right = crop.left + cropWidth;
+            } else {
+                int cropHeight = (int)((float)height / (float)width * frame.width());
+                crop.bottom = crop.top + cropHeight;
+            }
 
-                // Surfaceflinger is not aware of orientation, so convert our logical
-                // crop to surfaceflinger's portrait orientation.
-                convertCropForSurfaceFlinger(crop, rot, dw, dh);
+            // The screenshot API does not apply the current screen rotation.
+            int rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
 
-                if (DEBUG_SCREENSHOT) {
-                    Slog.i(TAG_WM, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
-                            + maxLayer + " appToken=" + appToken);
-                    for (int i = 0; i < windows.size(); i++) {
-                        WindowState win = windows.get(i);
-                        Slog.i(TAG_WM, win + ": " + win.mLayer
-                                + " animLayer=" + win.mWinAnimator.mAnimLayer
-                                + " surfaceLayer=" + win.mWinAnimator.mSurfaceController.getLayer());
-                    }
-                }
+            if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
+                rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
+            }
 
-                ScreenRotationAnimation screenRotationAnimation =
-                        mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
-                final boolean inRotation = screenRotationAnimation != null &&
-                        screenRotationAnimation.isAnimating();
-                if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG_WM,
-                        "Taking screenshot while rotating");
+            // Surfaceflinger is not aware of orientation, so convert our logical
+            // crop to surfaceflinger's portrait orientation.
+            convertCropForSurfaceFlinger(crop, rot, dw, dh);
 
-                bm = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer,
-                        inRotation, rot);
-                if (bm == null) {
-                    Slog.w(TAG_WM, "Screenshot failure taking screenshot for (" + dw + "x" + dh
-                            + ") to layer " + maxLayer);
-                    return null;
+            if (DEBUG_SCREENSHOT) {
+                Slog.i(TAG_WM, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
+                        + maxLayer + " appToken=" + appToken);
+                for (int i = 0; i < windows.size(); i++) {
+                    WindowState win = windows.get(i);
+                    Slog.i(TAG_WM, win + ": " + win.mLayer
+                            + " animLayer=" + win.mWinAnimator.mAnimLayer
+                            + " surfaceLayer=" + win.mWinAnimator.mSurfaceController.getLayer());
                 }
             }
 
-            break;
+            ScreenRotationAnimation screenRotationAnimation =
+                    mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
+            final boolean inRotation = screenRotationAnimation != null &&
+                    screenRotationAnimation.isAnimating();
+            if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG_WM,
+                    "Taking screenshot while rotating");
+
+            bm = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer,
+                    inRotation, rot);
+            if (bm == null) {
+                Slog.w(TAG_WM, "Screenshot failure taking screenshot for (" + dw + "x" + dh
+                        + ") to layer " + maxLayer);
+                return null;
+            }
         }
 
         if (DEBUG_SCREENSHOT) {