• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.wm.shell.windowdecor.common.viewhost
17 
18 import android.content.Context
19 import android.os.Trace
20 import android.util.Pools
21 import android.view.Display
22 import android.view.SurfaceControl
23 import com.android.wm.shell.shared.annotations.ShellMainThread
24 import com.android.wm.shell.sysui.ShellInit
25 import kotlinx.coroutines.CoroutineScope
26 import kotlinx.coroutines.launch
27 
28 /**
29  * A [WindowDecorViewHostSupplier] backed by a pool to allow recycling view hosts which may be
30  * expensive to recreate for each new or updated window decoration.
31  *
32  * Callers can obtain a [WindowDecorViewHost] using [acquire], which will return a pooled object if
33  * available, or create a new instance and return it if needed. When finished using a
34  * [WindowDecorViewHost], it must be released using [release] to allow it to be sent back into the
35  * pool and reused later on.
36  *
37  * This class also supports pre-warming [ReusableWindowDecorViewHost] instances, which will be put
38  * into the pool immediately after creation.
39  */
40 class PooledWindowDecorViewHostSupplier(
41     private val context: Context,
42     @ShellMainThread private val mainScope: CoroutineScope,
43     shellInit: ShellInit,
44     maxPoolSize: Int,
45     private val preWarmSize: Int,
46 ) : WindowDecorViewHostSupplier<WindowDecorViewHost> {
47 
48     private val pool: Pools.Pool<WindowDecorViewHost> = Pools.SynchronizedPool(maxPoolSize)
49     private var nextDecorViewHostId = 0
50 
51     init {
<lambda>null52         require(preWarmSize <= maxPoolSize) { "Pre-warm size should not exceed pool size" }
53         shellInit.addInitCallback(this::onShellInit, this)
54     }
55 
onShellInitnull56     private fun onShellInit() {
57         if (preWarmSize <= 0) {
58             return
59         }
60         preWarmViewHosts(preWarmSize)
61     }
62 
preWarmViewHostsnull63     private fun preWarmViewHosts(preWarmSize: Int) {
64         mainScope.launch {
65             // Applying isn't needed, as the surface was never actually shown.
66             val t = SurfaceControl.Transaction()
67             repeat(preWarmSize) {
68                 val warmedViewHost = newInstance(context, context.display).apply { warmUp() }
69                 // Put the warmed view host in the pool by releasing it.
70                 release(warmedViewHost, t)
71             }
72         }
73     }
74 
acquirenull75     override fun acquire(context: Context, display: Display): WindowDecorViewHost {
76         val pooledViewHost = pool.acquire()
77         if (pooledViewHost != null) {
78             return pooledViewHost
79         }
80         Trace.beginSection("PooledWindowDecorViewHostSupplier#acquire-newInstance")
81         val newDecorViewHost = newInstance(context, display)
82         Trace.endSection()
83         return newDecorViewHost
84     }
85 
releasenull86     override fun release(viewHost: WindowDecorViewHost, t: SurfaceControl.Transaction) {
87         val pooled = pool.release(viewHost)
88         if (!pooled) {
89             viewHost.release(t)
90         }
91     }
92 
newInstancenull93     private fun newInstance(context: Context, display: Display): ReusableWindowDecorViewHost {
94         // Use a reusable window decor view host, as it allows swapping the entire view hierarchy.
95         return ReusableWindowDecorViewHost(
96             context = context,
97             mainScope = mainScope,
98             display = display,
99             id = nextDecorViewHostId++,
100         )
101     }
102 }
103