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.example.tracing.demo
17 
18 import com.example.tracing.demo.experiments.CancellableSharedFlow
19 import com.example.tracing.demo.experiments.CollectFlow
20 import com.example.tracing.demo.experiments.CombineDeferred
21 import com.example.tracing.demo.experiments.Experiment
22 import com.example.tracing.demo.experiments.LaunchNested
23 import com.example.tracing.demo.experiments.LaunchSequentially
24 import com.example.tracing.demo.experiments.LeakySharedFlow
25 import com.example.tracing.demo.experiments.SharedFlowUsage
26 import com.example.tracing.demo.experiments.startThreadWithLooper
27 import dagger.Binds
28 import dagger.Component
29 import dagger.Module
30 import dagger.Provides
31 import dagger.multibindings.ClassKey
32 import dagger.multibindings.IntoMap
33 import javax.inject.Provider
34 import javax.inject.Qualifier
35 import javax.inject.Singleton
36 import kotlin.annotation.AnnotationRetention.RUNTIME
37 import kotlinx.coroutines.CoroutineDispatcher
38 import kotlinx.coroutines.Dispatchers
39 import kotlinx.coroutines.android.asCoroutineDispatcher
40 
41 @Qualifier @MustBeDocumented @Retention(RUNTIME) annotation class Main
42 
43 @Qualifier @MustBeDocumented @Retention(RUNTIME) annotation class Default
44 
45 @Qualifier @MustBeDocumented @Retention(RUNTIME) annotation class IO
46 
47 @Qualifier @MustBeDocumented @Retention(RUNTIME) annotation class Unconfined
48 
49 @Qualifier @MustBeDocumented @Retention(RUNTIME) annotation class FixedThreadA
50 
51 @Qualifier @MustBeDocumented @Retention(RUNTIME) annotation class FixedThreadB
52 
53 @Qualifier @MustBeDocumented @Retention(RUNTIME) annotation class FixedThreadC
54 
55 @Qualifier @MustBeDocumented @Retention(RUNTIME) annotation class FixedThreadD
56 
57 @Module
58 class ConcurrencyModule {
59 
60     @Provides
61     @Singleton
62     @Default
provideDefaultDispatchernull63     fun provideDefaultDispatcher(): CoroutineDispatcher {
64         return Dispatchers.Default
65     }
66 
67     @Provides
68     @Singleton
69     @IO
provideIODispatchernull70     fun provideIODispatcher(): CoroutineDispatcher {
71         return Dispatchers.IO
72     }
73 
74     @Provides
75     @Singleton
76     @Unconfined
provideUnconfinedDispatchernull77     fun provideUnconfinedDispatcher(): CoroutineDispatcher {
78         return Dispatchers.Unconfined
79     }
80 
81     @Provides
82     @Singleton
83     @FixedThreadA
provideDispatcherAnull84     fun provideDispatcherA(): CoroutineDispatcher {
85         return startThreadWithLooper("Thread:A").threadHandler.asCoroutineDispatcher()
86     }
87 
88     @Provides
89     @Singleton
90     @FixedThreadB
provideDispatcherBnull91     fun provideDispatcherB(): CoroutineDispatcher {
92         return startThreadWithLooper("Thread:B").threadHandler.asCoroutineDispatcher()
93     }
94 
95     @Provides
96     @Singleton
97     @FixedThreadC
provideDispatcherCnull98     fun provideDispatcherC(): CoroutineDispatcher {
99         return startThreadWithLooper("Thread:C").threadHandler.asCoroutineDispatcher()
100     }
101 
102     @Provides
103     @Singleton
104     @FixedThreadD
provideDispatcherDnull105     fun provideDispatcherD(): CoroutineDispatcher {
106         return startThreadWithLooper("Thread:D").threadHandler.asCoroutineDispatcher()
107     }
108 }
109 
110 @Module
111 interface ExperimentModule {
112     @Binds
113     @IntoMap
114     @ClassKey(CollectFlow::class)
bindCollectFlownull115     fun bindCollectFlow(service: CollectFlow): Experiment
116 
117     @Binds
118     @IntoMap
119     @ClassKey(SharedFlowUsage::class)
120     fun bindSharedFlowUsage(service: SharedFlowUsage): Experiment
121 
122     @Binds
123     @IntoMap
124     @ClassKey(LeakySharedFlow::class)
125     fun bindLeakySharedFlow(service: LeakySharedFlow): Experiment
126 
127     @Binds
128     @IntoMap
129     @ClassKey(CancellableSharedFlow::class)
130     fun bindCancellableSharedFlow(service: CancellableSharedFlow): Experiment
131 
132     @Binds
133     @IntoMap
134     @ClassKey(CombineDeferred::class)
135     fun bindCombineDeferred(service: CombineDeferred): Experiment
136 
137     @Binds
138     @IntoMap
139     @ClassKey(LaunchNested::class)
140     fun bindLaunchNested(service: LaunchNested): Experiment
141 
142     @Binds
143     @IntoMap
144     @ClassKey(LaunchSequentially::class)
145     fun bindLaunchSequentially(service: LaunchSequentially): Experiment
146 }
147 
148 @Singleton
149 @Component(modules = [ConcurrencyModule::class, ExperimentModule::class])
150 interface ApplicationComponent {
151     /** Returns [Experiment]s that should be used with the application. */
152     @Singleton fun getAllExperiments(): Map<Class<*>, Provider<Experiment>>
153 }
154