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.systemui.util.concurrency 17 18 import android.os.Handler 19 import android.os.HandlerThread 20 import android.os.Looper 21 import android.os.Process 22 import android.view.Choreographer 23 import com.android.systemui.Dependency 24 import com.android.systemui.Flags 25 import com.android.systemui.dagger.SysUISingleton 26 import com.android.systemui.dagger.qualifiers.Background 27 import com.android.systemui.dagger.qualifiers.BroadcastRunning 28 import com.android.systemui.dagger.qualifiers.LongRunning 29 import com.android.systemui.dagger.qualifiers.Main 30 import com.android.systemui.dagger.qualifiers.NotifInflation 31 import dagger.Module 32 import dagger.Provides 33 import java.util.concurrent.Executor 34 import javax.inject.Named 35 import javax.inject.Qualifier 36 37 @Qualifier 38 @MustBeDocumented 39 @Retention(AnnotationRetention.RUNTIME) 40 annotation class BackPanelUiThread 41 42 /** Dagger Module for classes found within the concurrent package. */ 43 @Module 44 object SysUIConcurrencyModule { 45 // Slow BG executor can potentially affect UI if UI is waiting for an updated state from this 46 // thread 47 private const val BG_SLOW_DISPATCH_THRESHOLD = 1000L 48 private const val BG_SLOW_DELIVERY_THRESHOLD = 1000L 49 private const val LONG_SLOW_DISPATCH_THRESHOLD = 2500L 50 private const val LONG_SLOW_DELIVERY_THRESHOLD = 2500L 51 private const val BROADCAST_SLOW_DISPATCH_THRESHOLD = 1000L 52 private const val BROADCAST_SLOW_DELIVERY_THRESHOLD = 1000L 53 private const val NOTIFICATION_INFLATION_SLOW_DISPATCH_THRESHOLD = 1000L 54 private const val NOTIFICATION_INFLATION_SLOW_DELIVERY_THRESHOLD = 1000L 55 56 /** 57 * Choreographer instance for the main thread. 58 * TODO(b/395887935): Lets move this to @Main and provide thread-local references 59 */ 60 @Provides 61 @SysUISingleton providesChoreographernull62 fun providesChoreographer(): Choreographer = Choreographer.getInstance() 63 64 /** Background Looper */ 65 @Provides 66 @SysUISingleton 67 @Background 68 fun provideBgLooper(): Looper { 69 val thread = HandlerThread("SysUiBg", Process.THREAD_PRIORITY_BACKGROUND) 70 thread.start() 71 thread 72 .getLooper() 73 .setSlowLogThresholdMs(BG_SLOW_DISPATCH_THRESHOLD, BG_SLOW_DELIVERY_THRESHOLD) 74 return thread.getLooper() 75 } 76 77 /** BroadcastRunning Looper (for sending and receiving broadcasts) */ 78 @Provides 79 @SysUISingleton 80 @BroadcastRunning provideBroadcastRunningLoopernull81 fun provideBroadcastRunningLooper(): Looper { 82 val thread = HandlerThread("BroadcastRunning", Process.THREAD_PRIORITY_BACKGROUND) 83 thread.start() 84 thread 85 .getLooper() 86 .setSlowLogThresholdMs( 87 BROADCAST_SLOW_DISPATCH_THRESHOLD, 88 BROADCAST_SLOW_DELIVERY_THRESHOLD 89 ) 90 return thread.getLooper() 91 } 92 93 /** Long running tasks Looper */ 94 @Provides 95 @SysUISingleton 96 @LongRunning provideLongRunningLoopernull97 fun provideLongRunningLooper(): Looper { 98 val thread = HandlerThread("SysUiLng", Process.THREAD_PRIORITY_BACKGROUND) 99 thread.start() 100 thread 101 .getLooper() 102 .setSlowLogThresholdMs(LONG_SLOW_DISPATCH_THRESHOLD, LONG_SLOW_DELIVERY_THRESHOLD) 103 return thread.getLooper() 104 } 105 106 /** Notification inflation Looper */ 107 @Provides 108 @SysUISingleton 109 @NotifInflation provideNotifInflationLoopernull110 fun provideNotifInflationLooper(): Looper { 111 val thread = HandlerThread("NotifInflation", Process.THREAD_PRIORITY_BACKGROUND) 112 thread.start() 113 val looper = thread.getLooper() 114 looper.setSlowLogThresholdMs( 115 NOTIFICATION_INFLATION_SLOW_DISPATCH_THRESHOLD, 116 NOTIFICATION_INFLATION_SLOW_DELIVERY_THRESHOLD 117 ) 118 return looper 119 } 120 121 @Provides 122 @SysUISingleton 123 @BackPanelUiThread provideBackPanelUiThreadContextnull124 fun provideBackPanelUiThreadContext( 125 @Main mainLooper: Looper, 126 @Main mainHandler: Handler, 127 @Main mainExecutor: Executor 128 ): UiThreadContext { 129 return if (Flags.edgeBackGestureHandlerThread()) { 130 val thread = 131 HandlerThread("BackPanelUiThread", Process.THREAD_PRIORITY_DISPLAY).apply { 132 start() 133 looper.setSlowLogThresholdMs( 134 LONG_SLOW_DISPATCH_THRESHOLD, 135 LONG_SLOW_DELIVERY_THRESHOLD 136 ) 137 } 138 UiThreadContext( 139 thread.looper, 140 thread.threadHandler, 141 thread.threadExecutor, 142 thread.threadHandler.runWithScissors { Choreographer.getInstance() } 143 ) 144 } else { 145 UiThreadContext( 146 mainLooper, 147 mainHandler, 148 mainExecutor, 149 mainHandler.runWithScissors { Choreographer.getInstance() } 150 ) 151 } 152 } 153 154 /** 155 * Background Handler. 156 * 157 * Prefer the Background Executor when possible. 158 */ 159 @Provides 160 @Background provideBgHandlernull161 fun provideBgHandler(@Background bgLooper: Looper): Handler = Handler(bgLooper) 162 163 /** Provide a BroadcastRunning Executor (for sending and receiving broadcasts). */ 164 @Provides 165 @SysUISingleton 166 @BroadcastRunning 167 fun provideBroadcastRunningExecutor(@BroadcastRunning looper: Looper): Executor = 168 ExecutorImpl(looper) 169 170 /** Provide a Long running Executor. */ 171 @Provides 172 @SysUISingleton 173 @LongRunning 174 fun provideLongRunningExecutor(@LongRunning looper: Looper): Executor = ExecutorImpl(looper) 175 176 /** Provide a Long running Executor. */ 177 @Provides 178 @SysUISingleton 179 @LongRunning 180 fun provideLongRunningDelayableExecutor(@LongRunning looper: Looper): DelayableExecutor = 181 ExecutorImpl(looper) 182 183 /** Provide a Background-Thread Executor. */ 184 @Provides 185 @SysUISingleton 186 @Background 187 fun provideBackgroundExecutor(@Background looper: Looper): Executor = ExecutorImpl(looper) 188 189 /** Provide a Background-Thread Executor. */ 190 @Provides 191 @SysUISingleton 192 @Background 193 fun provideBackgroundDelayableExecutor(@Background looper: Looper): DelayableExecutor = 194 ExecutorImpl(looper) 195 196 /** Provide a Background-Thread Executor. */ 197 @Provides 198 @SysUISingleton 199 @Background 200 fun provideBackgroundRepeatableExecutor( 201 @Background exec: DelayableExecutor 202 ): RepeatableExecutor = RepeatableExecutorImpl(exec) 203 204 /** Provide a Main-Thread Executor. */ 205 @Provides 206 @SysUISingleton 207 @Main 208 fun provideMainRepeatableExecutor(@Main exec: DelayableExecutor): RepeatableExecutor = 209 RepeatableExecutorImpl(exec) 210 211 /** */ 212 @Provides 213 @Main 214 fun providesMainMessageRouter(@Main executor: DelayableExecutor): MessageRouter = 215 MessageRouterImpl(executor) 216 217 /** */ 218 @Provides 219 @Background 220 fun providesBackgroundMessageRouter(@Background executor: DelayableExecutor): MessageRouter = 221 MessageRouterImpl(executor) 222 223 /** */ 224 @Provides 225 @SysUISingleton 226 @Named(Dependency.TIME_TICK_HANDLER_NAME) 227 fun provideTimeTickHandler(): Handler { 228 val thread = HandlerThread("TimeTick") 229 thread.start() 230 return Handler(thread.getLooper()) 231 } 232 233 /** */ 234 @Provides 235 @SysUISingleton 236 @NotifInflation provideNotifInflationExecutornull237 fun provideNotifInflationExecutor(@NotifInflation looper: Looper): Executor = 238 ExecutorImpl(looper) 239 } 240