Fixed a few issues with starting windows

1. startingData was accessed on a different thread without a lock held.
This caused synchronization issues where startingData could be set to
null while the starting window was getting created.

2. In onFirstWindowDrawn, startingData was not being set to null if the
startingWindow didn't exist. That means if the startingWindow hadn't
been created yet, it would get created after the first window was drawn.

Fixes: 129654434
Test: Steps from bug no longer reproducible
Change-Id: Ic5086798082b9f312cbd5069a937eac95cff7a9c
(cherry picked from commit a8f07a7f59a7f9c42c162953873b36de4ddb4ca2)
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 75e34fb..d4c4e6a 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -478,7 +478,7 @@
                     outReasons.put(windowingMode,  APP_TRANSITION_WINDOWS_DRAWN);
                 } else {
                     outReasons.put(windowingMode,
-                            wtoken.startingData instanceof SplashScreenStartingData
+                            wtoken.mStartingData instanceof SplashScreenStartingData
                                     ? APP_TRANSITION_SPLASH_SCREEN
                                     : APP_TRANSITION_SNAPSHOT);
                 }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 8785b01..ff0ad2b 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -204,7 +204,7 @@
     boolean removed;
 
     // Information about an application starting window if displayed.
-    StartingData startingData;
+    StartingData mStartingData;
     WindowState startingWindow;
     StartingSurface startingSurface;
     boolean startingDisplayed;
@@ -386,8 +386,8 @@
             // it from behind the starting window, so there is no need for it to also be doing its
             // own stuff.
             win.cancelAnimation();
-            removeStartingWindow();
         }
+        removeStartingWindow();
         updateReportedVisibilityLocked();
     }
 
@@ -875,7 +875,7 @@
         if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
                 + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
 
-        if (startingData != null) {
+        if (mStartingData != null) {
             removeStartingWindow();
         }
 
@@ -1054,7 +1054,7 @@
             // If this is the last window and we had requested a starting transition window,
             // well there is no point now.
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData");
-            startingData = null;
+            mStartingData = null;
             if (mHiddenSetFromTransferredStartingWindow) {
                 // We set the hidden state to false for the token from a transferred starting window.
                 // We now reset it back to true since the starting window was the last window in the
@@ -1487,13 +1487,13 @@
             final long origId = Binder.clearCallingIdentity();
             try {
                 // Transfer the starting window over to the new token.
-                startingData = fromToken.startingData;
+                mStartingData = fromToken.mStartingData;
                 startingSurface = fromToken.startingSurface;
                 startingDisplayed = fromToken.startingDisplayed;
                 fromToken.startingDisplayed = false;
                 startingWindow = tStartingWindow;
                 reportedVisible = fromToken.reportedVisible;
-                fromToken.startingData = null;
+                fromToken.mStartingData = null;
                 fromToken.startingSurface = null;
                 fromToken.startingWindow = null;
                 fromToken.startingMoved = true;
@@ -1539,13 +1539,13 @@
                 Binder.restoreCallingIdentity(origId);
             }
             return true;
-        } else if (fromToken.startingData != null) {
+        } else if (fromToken.mStartingData != null) {
             // The previous app was getting ready to show a
             // starting window, but hasn't yet done so.  Steal it!
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
                     "Moving pending starting from " + fromToken + " to " + this);
-            startingData = fromToken.startingData;
-            fromToken.startingData = null;
+            mStartingData = fromToken.mStartingData;
+            fromToken.mStartingData = null;
             fromToken.startingMoved = true;
             scheduleAddStartingWindow();
             return true;
@@ -2043,7 +2043,7 @@
             return false;
         }
 
-        if (startingData != null) {
+        if (mStartingData != null) {
             return false;
         }
 
@@ -2124,7 +2124,7 @@
         }
 
         if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
-        startingData = new SplashScreenStartingData(mWmService, pkg,
+        mStartingData = new SplashScreenStartingData(mWmService, pkg,
                 theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                 getMergedOverrideConfiguration());
         scheduleAddStartingWindow();
@@ -2138,7 +2138,7 @@
         }
 
         if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
-        startingData = new SnapshotStartingData(mWmService, snapshot);
+        mStartingData = new SnapshotStartingData(mWmService, snapshot);
         scheduleAddStartingWindow();
         return true;
     }
@@ -2157,18 +2157,21 @@
 
         @Override
         public void run() {
+            // Can be accessed without holding the global lock
+            final StartingData startingData;
             synchronized (mWmService.mGlobalLock) {
                 // There can only be one adding request, silly caller!
                 mWmService.mAnimationHandler.removeCallbacks(this);
-            }
 
-            if (startingData == null) {
-                // Animation has been canceled... do nothing.
-                if (DEBUG_STARTING_WINDOW) {
-                    Slog.v(TAG, "startingData was nulled out before handling"
-                            + " mAddStartingWindow: " + AppWindowToken.this);
+                if (mStartingData == null) {
+                    // Animation has been canceled... do nothing.
+                    if (DEBUG_STARTING_WINDOW) {
+                        Slog.v(TAG, "startingData was nulled out before handling"
+                                + " mAddStartingWindow: " + AppWindowToken.this);
+                    }
+                    return;
                 }
-                return;
+                startingData = mStartingData;
             }
 
             if (DEBUG_STARTING_WINDOW) {
@@ -2186,20 +2189,21 @@
                 synchronized (mWmService.mGlobalLock) {
                     // If the window was successfully added, then
                     // we need to remove it.
-                    if (removed || startingData == null) {
+                    if (removed || mStartingData == null) {
                         if (DEBUG_STARTING_WINDOW) {
                             Slog.v(TAG, "Aborted starting " + AppWindowToken.this
-                                    + ": removed=" + removed + " startingData=" + startingData);
+                                    + ": removed=" + removed + " startingData=" + mStartingData);
                         }
                         startingWindow = null;
-                        startingData = null;
+                        mStartingData = null;
                         abort = true;
                     } else {
                         startingSurface = surface;
                     }
                     if (DEBUG_STARTING_WINDOW && !abort) {
-                        Slog.v(TAG, "Added starting " + AppWindowToken.this + ": startingWindow="
-                                + startingWindow + " startingView=" + startingSurface);
+                        Slog.v(TAG,
+                                "Added starting " + AppWindowToken.this + ": startingWindow="
+                                        + startingWindow + " startingView=" + startingSurface);
                     }
                 }
                 if (abort) {
@@ -2246,21 +2250,21 @@
 
     void removeStartingWindow() {
         if (startingWindow == null) {
-            if (startingData != null) {
+            if (mStartingData != null) {
                 // Starting window has not been added yet, but it is scheduled to be added.
                 // Go ahead and cancel the request.
                 if (DEBUG_STARTING_WINDOW) {
                     Slog.v(TAG_WM, "Clearing startingData for token=" + this);
                 }
-                startingData = null;
+                mStartingData = null;
             }
             return;
         }
 
         final WindowManagerPolicy.StartingSurface surface;
-        if (startingData != null) {
+        if (mStartingData != null) {
             surface = startingSurface;
-            startingData = null;
+            mStartingData = null;
             startingSurface = null;
             startingWindow = null;
             startingDisplayed = false;
@@ -2995,8 +2999,8 @@
             pw.print(prefix); pw.print("inPendingTransaction=");
                     pw.println(inPendingTransaction);
         }
-        if (startingData != null || removed || firstWindowDrawn || mIsExiting) {
-            pw.print(prefix); pw.print("startingData="); pw.print(startingData);
+        if (mStartingData != null || removed || firstWindowDrawn || mIsExiting) {
+            pw.print(prefix); pw.print("startingData="); pw.print(mStartingData);
                     pw.print(" removed="); pw.print(removed);
                     pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
                     pw.print(" mIsExiting="); pw.println(mIsExiting);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 064b553..834f4a2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -504,14 +504,14 @@
 
     private void assertHasStartingWindow(AppWindowToken atoken) {
         assertNotNull(atoken.startingSurface);
-        assertNotNull(atoken.startingData);
+        assertNotNull(atoken.mStartingData);
         assertNotNull(atoken.startingWindow);
     }
 
     private void assertNoStartingWindow(AppWindowToken atoken) {
         assertNull(atoken.startingSurface);
         assertNull(atoken.startingWindow);
-        assertNull(atoken.startingData);
+        assertNull(atoken.mStartingData);
         atoken.forAllWindows(windowState -> {
             assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING);
         }, true);