Fix several issues that retained WatchFaceService

It appears the WakeLock can sometimes retain the WatchFaceService,
adding a release() call fixes this.  Also the StateFlows can
retain WatchFaceService, cancelling the underlying CoroutineScopes
fixes that.

Test: Manual testing with AndroidStudio profiler
Bug: 237294238
Change-Id: I9296f53be46a96c30a76a094f94ad216ba03dbeb
(cherry picked from commit 403c9bf65a3866e99e4d26d12b9c0364c92aa05c)
Merged-In: I9296f53be46a96c30a76a094f94ad216ba03dbeb
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index c4ade27..07e5020 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -617,6 +617,8 @@
         }
     }
 
+    internal open fun cancelCoroutineScopesInOnDestroy() = true
+
     /**
      * This is open for use by tests, it allows them to inject a custom [SurfaceHolder].
      * @hide
@@ -1518,8 +1520,8 @@
             }
 
             // NB user code could throw an exception so do this last.
-            runBlocking {
-                try {
+            try {
+                runBlocking {
                     // The WatchFaceImpl is created on the UiThread so if we get here and it's not
                     // created we can be sure it'll never be created hence we don't need to destroy
                     // it.
@@ -1530,17 +1532,34 @@
                         watchFaceInitDetails
                             .await().watchFace.renderer.onDestroy()
                     }
-                } catch (e: Exception) {
-                    // Throwing an exception here leads to a cascade of errors, log instead.
-                    Log.e(
-                        TAG,
-                        "WatchFace exception observed in onDestroy (may have occurred during init)",
-                        e
-                    )
+                }
+            } catch (e: Exception) {
+                // Throwing an exception here leads to a cascade of errors, log instead.
+                Log.e(
+                    TAG,
+                    "WatchFace exception observed in onDestroy (may have occurred during init)",
+                    e
+                )
+            } finally {
+                if (this@EngineWrapper::ambientUpdateWakelock.isInitialized) {
+                    // Make sure the WakeLock doesn't retain the WatchFaceService.
+                    ambientUpdateWakelock.release()
+                }
+
+                // StateFlows may retain WatchFaceService via the coroutineScope. Call cancel to
+                // ensure resources are released. Headless watch faces call cancelCoroutineScopes
+                // themselves since they call onDestroy from a coroutine context.
+                if (cancelCoroutineScopesInOnDestroy() && !mutableWatchState.isHeadless) {
+                    cancelCoroutineScopes()
                 }
             }
         }
 
+        internal fun cancelCoroutineScopes() {
+            uiThreadCoroutineScope.cancel()
+            backgroundThreadCoroutineScope.cancel()
+        }
+
         override fun onSurfaceDestroyed(holder: SurfaceHolder) {
             surfaceDestroyed = true
         }
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/HeadlessWatchFaceImpl.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/HeadlessWatchFaceImpl.kt
index 40dfec1..461887f 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/HeadlessWatchFaceImpl.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/HeadlessWatchFaceImpl.kt
@@ -133,7 +133,8 @@
                         engine = null
                     }
                 }
-            }
+                engineCopy
+            }.cancelCoroutineScopes()
         }
     }
 }
diff --git a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/TestCommon.kt b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
index 7a01898..8646fdb 100644
--- a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
+++ b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/TestCommon.kt
@@ -77,6 +77,12 @@
 
     override fun forceIsVisibleForTesting() = forceIsVisible
 
+    /**
+     * [WatchFaceService.EngineWrapper.onDestroy] is called more than once in some tests which is a
+     * problem due to using a CoroutineScope after it's been cancelled leading to exceptions.
+     */
+    override fun cancelCoroutineScopesInOnDestroy() = false
+
     fun reset() {
         clearTappedState()
         complicationSelected = null