Skip to content

Commit

Permalink
Delay subcomponent generation (duckduckgo#2132)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/1202552961248957/1202710479869519/f

### Description

See the [asana task](https://app.asana.com/0/1202552961248957/1202710479869519/f) for full context and explanation

### Steps to test this PR

- [x] install from this branch
- [x] smoke tests for app and AppTP
- [x] filter logcat by `TrackerBlockingVpnService\$startVpn`
- [x] install from develop
- [x] enable AppTP (it should be disabled before)
- [x] record the logcat
- [x] install from this branch
- [x] enable AppTP (it should be disabled before)
- [x] verify the logcat is the same
  • Loading branch information
aitorvs authored Aug 8, 2022
1 parent 9b997bf commit 5c2e7f9
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.duckduckgo.anvil.compiler

import com.duckduckgo.anvil.annotations.InjectWith
import com.google.auto.service.AutoService
import com.squareup.anvil.annotations.ContributesSubcomponent
import com.squareup.anvil.annotations.ContributesTo
import com.squareup.anvil.annotations.ExperimentalAnvilApi
import com.squareup.anvil.annotations.MergeSubcomponent
Expand All @@ -30,6 +31,7 @@ import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferenc
import com.squareup.kotlinpoet.*
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import dagger.Binds
import dagger.BindsInstance
import dagger.Subcomponent
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
Expand Down Expand Up @@ -73,16 +75,27 @@ class ContributesSubComponentCodeGenerator : CodeGenerator {
.builder(singleInstanceAnnotationFqName.asClassName(module)).addMember("scope = %T::class", scope.asClassName())
.build()
)
.addAnnotation(AnnotationSpec.builder(MergeSubcomponent::class).addMember("scope = %T::class", scope.asClassName()).build())
.addAnnotation(scope.fqName.subComponentAnnotation(module))
.addSuperinterface(duckduckgoAndroidInjectorFqName.asClassName(module).parameterizedBy(vmClass.asClassName()))
.addType(
TypeSpec.interfaceBuilder("Factory")
.addSuperinterface(
duckduckgoAndroidInjectorFqName.asClassName(module)
.nestedClass("Factory")
.parameterizedBy(vmClass.asClassName())
.parameterizedBy(vmClass.asClassName(), FqName(subcomponentFactoryClassName).asClassName(module))
)
.addAnnotation(scope.fqName.subComponentFactoryAnnotation(module))
.addFunction(
// This function should follow the [AndroidInjector.Factory.create] signature
FunSpec.builder("create")
.addModifiers(KModifier.OVERRIDE)
.addModifiers(KModifier.ABSTRACT)
.addParameter(
ParameterSpec.builder("instance", vmClass.asClassName()).addAnnotation(BindsInstance::class).build()
)
.returns(FqName(subcomponentFactoryClassName).asClassName(module))
.build()
)
.addAnnotation(AnnotationSpec.builder(Subcomponent.Factory::class).build())
.build()
)
.addType(generateParentComponentInterface(vmClass, codeGenDir, module))
Expand Down Expand Up @@ -144,7 +157,7 @@ class ContributesSubComponentCodeGenerator : CodeGenerator {
AnnotationSpec.builder(ClassKey::class).addMember("%T::class", bindingClassKey.asClassName(module)).build()
)
.addModifiers(KModifier.ABSTRACT)
.returns(duckduckgoAndroidInjectorFqName.asClassName(module).nestedClass("Factory").parameterizedBy(STAR))
.returns(duckduckgoAndroidInjectorFqName.asClassName(module).nestedClass("Factory").parameterizedBy(STAR, STAR))
.build()
)
.build()
Expand All @@ -155,6 +168,25 @@ class ContributesSubComponentCodeGenerator : CodeGenerator {

}

private fun FqName.subComponentAnnotation(module: ModuleDescriptor): AnnotationSpec {
return if (this == vpnScopeFqName) {
AnnotationSpec.builder(ContributesSubcomponent::class)
.addMember("scope = %T::class", this.asClassName(module))
.addMember("parentScope = %T::class", getParentScope(module).asClassName(module))
.build()
} else {
AnnotationSpec.builder(MergeSubcomponent::class).addMember("scope = %T::class", this.asClassName(module)).build()
}
}

private fun FqName.subComponentFactoryAnnotation(module: ModuleDescriptor): AnnotationSpec {
return if (this == vpnScopeFqName) {
AnnotationSpec.builder(ContributesSubcomponent.Factory::class).build()
} else {
AnnotationSpec.builder(Subcomponent.Factory::class).build()
}
}

private fun FqName.getParentScope(module: ModuleDescriptor): FqName {
return when (this.asClassName(module)) {
activityScopeFqName.asClassName(module) -> appScopeFqName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import dagger.multibindings.IntoMap
)
interface VpnInternalSettingsActivityComponent : AndroidInjector<VpnInternalSettingsActivity> {
@Subcomponent.Factory
interface Factory : AndroidInjector.Factory<VpnInternalSettingsActivity>
interface Factory : AndroidInjector.Factory<VpnInternalSettingsActivity, VpnInternalSettingsActivityComponent>
}

@ContributesTo(AppScope::class)
Expand All @@ -51,5 +51,5 @@ abstract class VpnInternalSettingsActivityBindingModule {
@Binds
@IntoMap
@ClassKey(VpnInternalSettingsActivity::class)
abstract fun VpnInternalSettingsActivityComponent.Factory.bind(): AndroidInjector.Factory<*>
abstract fun VpnInternalSettingsActivityComponent.Factory.bind(): AndroidInjector.Factory<*, *>
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ open class DuckDuckGoApplication : HasDaggerInjector, Application() {
lateinit var appCoroutineScope: CoroutineScope

@Inject
lateinit var injectorFactoryMap: DaggerMap<Class<*>, AndroidInjector.Factory<*>>
lateinit var injectorFactoryMap: DaggerMap<Class<*>, AndroidInjector.Factory<*, *>>

private val processDetector = ProcessDetector()

Expand Down Expand Up @@ -211,7 +211,7 @@ open class DuckDuckGoApplication : HasDaggerInjector, Application() {
*
* This method will return the [AndroidInjector.Factory] for the given key passed in as parameter.
*/
override fun daggerFactoryFor(key: Class<*>): AndroidInjector.Factory<*> {
override fun daggerFactoryFor(key: Class<*>): AndroidInjector.Factory<*, *> {
return injectorFactoryMap[key]
?: throw RuntimeException(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import com.duckduckgo.app.global.DispatcherProvider
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.app.utils.ConflatedJob
import com.duckduckgo.bandwidth.impl.BandwidthPixelName.APPTP_BANDWIDTH
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.di.scopes.VpnScope
import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks
import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason
import com.squareup.anvil.annotations.ContributesMultibinding
Expand All @@ -32,10 +32,10 @@ import java.util.concurrent.TimeUnit
import javax.inject.Inject

@ContributesMultibinding(
scope = AppScope::class,
scope = VpnScope::class,
boundType = VpnServiceCallbacks::class
)
@SingleInstanceIn(AppScope::class)
@SingleInstanceIn(VpnScope::class)
class AppTpBandwidthCollector @Inject constructor(
private val context: Context,
private val bandwidthRepository: BandwidthRepository,
Expand Down
10 changes: 5 additions & 5 deletions di/src/main/java/dagger/android/AndroidInjector.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ interface HasDaggerInjector {
* 1. creating the dagger component
* 2. inject the dependencies in the Android type (eg. Activity)
*/
fun daggerFactoryFor(key: Class<*>): AndroidInjector.Factory<*>
fun daggerFactoryFor(key: Class<*>): AndroidInjector.Factory<*, *>
}

interface AndroidInjector<T> {
Expand All @@ -45,12 +45,12 @@ interface AndroidInjector<T> {
*
* @param <T> the concrete type to be injected
*/
interface Factory<T> {
interface Factory<T, SubComponentType : AndroidInjector<T>> {
/**
* Creates an {@link AndroidInjector} for {@code instance}. This should be the same instance
* that will be passed to {@link #inject(Object)}.
*/
fun create(@BindsInstance instance: T): AndroidInjector<T>
fun create(@BindsInstance instance: T): SubComponentType
}

companion object {
Expand All @@ -61,13 +61,13 @@ interface AndroidInjector<T> {
* 2. Use the factory to create the dagger component that relates to an Android type, eg. Activity
* 3. Inject any dependency requested by the Android type
*/
inline fun <reified T> inject(
inline fun <reified T, R : AndroidInjector<T>> inject(
injector: Any,
instance: T,
mapKey: Class<*>? = null
) {
if ((injector is HasDaggerInjector)) {
(injector.daggerFactoryFor(mapKey ?: instance!!::class.java) as Factory<T>)
(injector.daggerFactoryFor(mapKey ?: instance!!::class.java) as Factory<T, R>)
.create(instance)
.inject(instance)
} else {
Expand Down
4 changes: 2 additions & 2 deletions di/src/main/java/dagger/android/DaggerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ import javax.inject.Inject

abstract class DaggerActivity : AppCompatActivity(), HasDaggerInjector {
@Inject
lateinit var injectorFactoryMap: DaggerMap<Class<*>, AndroidInjector.Factory<*>>
lateinit var injectorFactoryMap: DaggerMap<Class<*>, AndroidInjector.Factory<*, *>>

override fun daggerFactoryFor(key: Class<*>): AndroidInjector.Factory<*> {
override fun daggerFactoryFor(key: Class<*>): AndroidInjector.Factory<*, *> {
return injectorFactoryMap[key]
?: throw RuntimeException(
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package com.duckduckgo.vpn.internal.feature.logs

import android.content.Context
import android.content.Intent
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.di.scopes.VpnScope
import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks
import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason
import com.duckduckgo.vpn.internal.feature.InternalFeatureReceiver
Expand Down Expand Up @@ -59,7 +59,7 @@ class DebugLoggingReceiver(
}
}

@ContributesMultibinding(AppScope::class)
@ContributesMultibinding(VpnScope::class)
class DebugLoggingReceiverRegister @Inject constructor(
private val context: Context
) : VpnServiceCallbacks {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ package com.duckduckgo.vpn.internal.feature.remote
import android.content.Context
import android.content.Intent
import com.duckduckgo.app.global.DispatcherProvider
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.di.scopes.VpnScope
import com.duckduckgo.mobile.android.vpn.feature.*
import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks
import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason
Expand Down Expand Up @@ -89,7 +89,7 @@ class VpnRemoteFeatureReceiver(
}
}

@ContributesMultibinding(AppScope::class)
@ContributesMultibinding(VpnScope::class)
class VpnRemoteFeatureReceiverRegister @Inject constructor(
private val context: Context,
private val appTpFeatureConfig: AppTpFeatureConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.di.scopes.VpnScope
import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks
import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason
import com.duckduckgo.mobile.android.vpn.trackers.AppTrackerExceptionRule
Expand Down Expand Up @@ -72,7 +72,7 @@ class ExceptionRulesDebugReceiver(
}
}

@ContributesMultibinding(AppScope::class)
@ContributesMultibinding(VpnScope::class)
class ExceptionRulesDebugReceiverRegister @Inject constructor(
private val context: Context,
private val exclusionRulesRepository: ExclusionRulesRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package com.duckduckgo.vpn.internal.feature.trackers
import android.content.Context
import android.content.Intent
import com.duckduckgo.app.di.AppCoroutineScope
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.di.scopes.VpnScope
import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks
import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason
import com.duckduckgo.mobile.android.vpn.store.VpnDatabase
Expand Down Expand Up @@ -50,7 +50,7 @@ class DeleteTrackersDebugReceiver(
}
}

@ContributesMultibinding(AppScope::class)
@ContributesMultibinding(VpnScope::class)
class DeleteTrackersDebugReceiverRegister @Inject constructor(
private val context: Context,
private val vpnDatabase: VpnDatabase,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package com.duckduckgo.vpn.internal.feature.transparency
import android.content.Context
import android.content.Intent
import com.duckduckgo.app.utils.ConflatedJob
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.di.scopes.VpnScope
import com.duckduckgo.mobile.android.vpn.service.VpnServiceCallbacks
import com.duckduckgo.mobile.android.vpn.state.VpnStateMonitor.VpnStopReason
import com.duckduckgo.vpn.internal.feature.InternalFeatureReceiver
Expand Down Expand Up @@ -68,7 +68,7 @@ class TransparencyModeDebugReceiver(
}
}

@ContributesMultibinding(AppScope::class)
@ContributesMultibinding(VpnScope::class)
class ExceptionRulesDebugReceiverRegister @Inject constructor(
private val context: Context,
private val trackerDetectorInterceptor: TransparencyTrackerDetectorInterceptor
Expand Down

0 comments on commit 5c2e7f9

Please sign in to comment.