Add RootComponentGenerator to auto-generate root components for different dialer variants.

Bug: 35612086
Test: Test included
PiperOrigin-RevId: 189981890
Change-Id: Ife99969189d5d37bb1ad8ba61361a51e78abdfbb
diff --git a/Android.mk b/Android.mk
index 5957458..7d945fe 100644
--- a/Android.mk
+++ b/Android.mk
@@ -37,6 +37,10 @@
 EXCLUDE_FILES += \
 	$(BASE_DIR)/contacts/common/format/testing/SpannedTestUtils.java
 
+# Exclude rootcomponentgenerator
+EXCLUDE_FILES += \
+	$(call all-java-files-under, $(BASE_DIR)/dialer/rootcomponentgenerator/processor)
+
 # Exclude build variants for now
 EXCLUDE_FILES += \
 	$(BASE_DIR)/dialer/constants/googledialer/ConstantsImpl.java \
@@ -142,10 +146,10 @@
 	dialer-guava \
 	dialer-javax-annotation-api \
 	dialer-javax-inject \
+	dialer-rootcomponentprocessor
 
 LOCAL_ANNOTATION_PROCESSOR_CLASSES := \
-  com.google.auto.value.processor.AutoValueProcessor,dagger.internal.codegen.ComponentProcessor,com.bumptech.glide.annotation.compiler.GlideAnnotationProcessor
-
+  com.google.auto.value.processor.AutoValueProcessor,dagger.internal.codegen.ComponentProcessor,com.bumptech.glide.annotation.compiler.GlideAnnotationProcessor,com.android.dialer.rootcomponentgenerator.processor.RootComponentProcessor
 
 # Begin Bug: 37077388
 LOCAL_DX_FLAGS := --multi-dex
@@ -203,6 +207,8 @@
     dialer-javax-annotation-api:../../../prebuilts/tools/common/m2/repository/javax/annotation/javax.annotation-api/1.2/javax.annotation-api-1.2.jar \
     dialer-javax-inject:../../../prebuilts/tools/common/m2/repository/javax/inject/javax.inject/1/javax.inject-1.jar \
     dialer-javapoet:../../../prebuilts/tools/common/m2/repository/com/squareup/javapoet/1.8.0/javapoet-1.8.0.jar \
+    dialer-auto-service:../../../prebuilts/tools/common/m2/repository/com/google/auto/service/auto-service/1.0-rc2/auto-service-1.0-rc2.jar \
+    dialer-auto-common:../../../prebuilts/tools/common/m2/repository/com/google/auto/auto-common/0.9/auto-common-0.9.jar \
 
 include $(BUILD_HOST_PREBUILT)
 
@@ -420,3 +426,29 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_MODULE := dialer-rootcomponentprocessor
+LOCAL_MODULE_CLASS := JAVA_LIBRARIES
+LOCAL_IS_HOST_MODULE := true
+BASE_DIR := java/com/android
+
+LOCAL_SRC_FILES := \
+	$(call all-java-files-under, $(BASE_DIR)/dialer/rootcomponentgenerator/annotation) \
+	$(call all-java-files-under, $(BASE_DIR)/dialer/rootcomponentgenerator/processor)
+
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+	dialer-guava \
+	dialer-dagger2 \
+	dialer-javapoet \
+	dialer-auto-service \
+	dialer-auto-common \
+	dialer-javax-annotation-api \
+	dialer-javax-inject
+
+$(info $(LOCAL_STATIC_JAVA_LIBRARIES))
+
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
diff --git a/java/com/android/dialer/rootcomponentgenerator/annotation/DialerComponent.java b/java/com/android/dialer/rootcomponentgenerator/annotation/DialerComponent.java
new file mode 100644
index 0000000..573abae
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/annotation/DialerComponent.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.rootcomponentgenerator.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a type equivalent to {@link dagger.Subcomponent}.
+ *
+ * <p>The annotation processor will generate a new type file with some prefix, which contains public
+ * static XXX get(Context context) method and HasComponent interface like:
+ *
+ * <p>
+ *
+ * <pre>
+ * <code>
+ *  public static SimulatorComponent get(Context context) {
+ *      HasRootComponent hasRootComponent = (HasRootComponent) context.getApplicationContext();
+ *      return ((HasComponent)(hasRootComponent.component()).simulatorComponent();
+ *  }
+ *  public interface HasComponent {
+ *      SimulatorComponent simulatorComponent();
+ *  }
+ * </code>
+ * </pre>
+ */
+@Target(ElementType.TYPE)
+public @interface DialerComponent {
+  Class<?>[] modules() default {};
+}
diff --git a/java/com/android/dialer/rootcomponentgenerator/annotation/DialerRootComponent.java b/java/com/android/dialer/rootcomponentgenerator/annotation/DialerRootComponent.java
new file mode 100644
index 0000000..b6bf22e
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/annotation/DialerRootComponent.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.rootcomponentgenerator.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates the place with this annotation when a RootComponent is needed.
+ *
+ * <p>Usually users put this annotation on application class that is root of dependencies (the last
+ * thing to compile). The annotation processor will figure out what it needs to generate a variant
+ * root through dependencies.
+ *
+ * <p>Example:
+ *
+ * <pre>
+ * <code>
+ * @DialerRootComponent(variant = DialerVariant.DIALER_AOSP)
+ * public class RootDialerAosp {}
+ * </code>
+ * </pre>
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.SOURCE)
+public @interface DialerRootComponent {
+  DialerVariant variant();
+}
diff --git a/java/com/android/dialer/rootcomponentgenerator/annotation/DialerVariant.java b/java/com/android/dialer/rootcomponentgenerator/annotation/DialerVariant.java
new file mode 100644
index 0000000..0bb1852
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/annotation/DialerVariant.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.rootcomponentgenerator.annotation;
+
+/** Represents all dialer variants. */
+public enum DialerVariant {
+  // AOSP Dialer variants
+  DIALER_AOSP("DialerAosp"),
+  DIALER_AOSP_ESPRESSO("DialerAospEspresso"),
+  DIALER_ROBOLECTRIC("DialerRobolectric"),
+
+
+
+  // TEST variant will be used in situations where we need create in-test application class which
+  // doesn't belong to any variants listed above
+  DIALER_TEST("DialerTest");
+
+  private final String variant;
+
+  DialerVariant(String variant) {
+    this.variant = variant;
+  }
+
+  @Override
+  public String toString() {
+    return variant;
+  }
+}
diff --git a/java/com/android/dialer/rootcomponentgenerator/annotation/InstallIn.java b/java/com/android/dialer/rootcomponentgenerator/annotation/InstallIn.java
new file mode 100644
index 0000000..01a7873
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/annotation/InstallIn.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.rootcomponentgenerator.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for {@link dagger.Module dagger.Modules} which causes them to be installed in the
+ * specified variants.
+ *
+ * <p>It has a parameter for users to enter on which variants annotated module will be installed and
+ * also must be non-empty. Example:
+ *
+ * <pre>
+ * <code>
+ * @InstallIn(variants = {DialerVariant.DIALER_AOSP, DialerVariant.DIALER_TEST})
+ * public class Module1 {}
+ *
+ * </code>
+ * </pre>
+ */
+@Target(ElementType.TYPE)
+public @interface InstallIn {
+  DialerVariant[] variants();
+}
diff --git a/java/com/android/dialer/rootcomponentgenerator/annotation/RootComponentGeneratorMetadata.java b/java/com/android/dialer/rootcomponentgenerator/annotation/RootComponentGeneratorMetadata.java
new file mode 100644
index 0000000..070cc73
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/annotation/RootComponentGeneratorMetadata.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.rootcomponentgenerator.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Only used by rootcomponent generator to store metadata for locating annotated
+ * (@DialerComponent, @InstallIn) class.
+ */
+@Target(ElementType.TYPE)
+public @interface RootComponentGeneratorMetadata {
+  String tag();
+
+  Class<?> annotatedClass();
+}
diff --git a/java/com/android/dialer/rootcomponentgenerator/processor/ComponentGeneratingStep.java b/java/com/android/dialer/rootcomponentgenerator/processor/ComponentGeneratingStep.java
new file mode 100644
index 0000000..8605499
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/processor/ComponentGeneratingStep.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.rootcomponentgenerator.processor;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static javax.lang.model.element.Modifier.ABSTRACT;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+import static javax.lang.model.util.ElementFilter.typesIn;
+
+import com.android.dialer.rootcomponentgenerator.annotation.DialerComponent;
+import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.auto.common.MoreElements;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.Subcomponent;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+
+/**
+ * Generates component for a type annotated with {@link DialerComponent}.
+ *
+ * <p>Our components have boilerplate code like:
+ *
+ * <p>
+ *
+ * <pre>
+ * <code>
+ *
+ * {@literal @}dagger.Subcomponent
+ * public abstract class GenXXXXComponent {
+ *   public static SimulatorComponent get(Context context) {
+ *      return ((HasComponent)((HasRootComponent) context.getApplicationContext()).component())
+ *         .simulatorComponent();
+ *   }
+ *   public interface HasComponent {
+ *      SimulatorComponent simulatorComponent();
+ *  }
+ * }
+ * </code>
+ * </pre>
+ */
+final class ComponentGeneratingStep implements ProcessingStep {
+
+  private static final String DIALER_INJECT_PACKAGE = "com.android.dialer.inject";
+  private static final String DIALER_HASROOTCOMPONENT_INTERFACE = "HasRootComponent";
+  private static final ClassName ANDROID_CONTEXT_CLASS_NAME =
+      ClassName.get("android.content", "Context");
+  private final ProcessingEnvironment processingEnv;
+
+  public ComponentGeneratingStep(ProcessingEnvironment processingEnv) {
+    this.processingEnv = processingEnv;
+  }
+
+  @Override
+  public Set<? extends Class<? extends Annotation>> annotations() {
+    return ImmutableSet.of(DialerComponent.class);
+  }
+
+  @Override
+  public Set<? extends Element> process(
+      SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+    for (TypeElement type : typesIn(elementsByAnnotation.get(DialerComponent.class))) {
+      generateComponent(type);
+    }
+    return Collections.emptySet();
+  }
+
+  /**
+   * Generates component file for a componentElement.
+   *
+   * <p>The annotation processor will generate a new type file with some prefix, which contains
+   * public static XXX get(Context context) method and HasComponent interface.
+   *
+   * @param dialerComponentElement a component used by the annotation processor.
+   */
+  private void generateComponent(TypeElement dialerComponentElement) {
+    TypeSpec.Builder componentClass =
+        dialerComponentElement.getKind().isClass()
+            ? cloneClass(dialerComponentElement, RootComponentUtils.GENERATED_COMPONENT_PREFIX)
+            : cloneInterface(dialerComponentElement, RootComponentUtils.GENERATED_COMPONENT_PREFIX);
+    componentClass.addAnnotation(makeDaggerSubcomponentAnnotation(dialerComponentElement));
+    RootComponentUtils.writeJavaFile(
+        processingEnv,
+        ClassName.get(dialerComponentElement).packageName(),
+        dialerBoilerplateCode(componentClass, dialerComponentElement));
+  }
+
+  @SuppressWarnings("unchecked")
+  private AnnotationSpec makeDaggerSubcomponentAnnotation(TypeElement dialerComponentElement) {
+
+    Optional<AnnotationMirror> componentMirror =
+        getAnnotationMirror(dialerComponentElement, DialerComponent.class);
+
+    AnnotationSpec.Builder subcomponentBuilder = AnnotationSpec.builder(Subcomponent.class);
+    for (AnnotationValue annotationValue :
+        (List<? extends AnnotationValue>)
+            getAnnotationValue(componentMirror.get(), "modules").getValue()) {
+      subcomponentBuilder.addMember(
+          "modules", "$T.class", ClassName.get((TypeMirror) annotationValue.getValue()));
+    }
+    return subcomponentBuilder.build();
+  }
+
+  private TypeSpec dialerBoilerplateCode(
+      TypeSpec.Builder typeBuilder, TypeElement dialerComponentElement) {
+    return typeBuilder
+        .addType(hasComponentInterface(typeBuilder, dialerComponentElement))
+        .addMethod(addGetComponentMethod(typeBuilder, dialerComponentElement))
+        .build();
+  }
+
+  private TypeSpec hasComponentInterface(
+      TypeSpec.Builder typeBuilder, TypeElement dialerComponentElement) {
+    return TypeSpec.interfaceBuilder("HasComponent")
+        .addModifiers(PUBLIC)
+        .addMethod(
+            MethodSpec.methodBuilder("make" + dialerComponentElement.getSimpleName())
+                .addModifiers(PUBLIC, ABSTRACT)
+                .returns(getComponentClass(typeBuilder, dialerComponentElement))
+                .build())
+        .build();
+  }
+
+  private MethodSpec addGetComponentMethod(
+      TypeSpec.Builder typeBuilder, TypeElement dialerComponentElement) {
+    ClassName hasComponenetInterface =
+        ClassName.get(
+                getPackageName(dialerComponentElement),
+                RootComponentUtils.GENERATED_COMPONENT_PREFIX
+                    + dialerComponentElement.getSimpleName())
+            .nestedClass("HasComponent");
+    ClassName hasRootComponentInterface =
+        ClassName.get(DIALER_INJECT_PACKAGE, DIALER_HASROOTCOMPONENT_INTERFACE);
+    return MethodSpec.methodBuilder("get")
+        .addModifiers(PUBLIC, STATIC)
+        .addParameter(ParameterSpec.builder(ANDROID_CONTEXT_CLASS_NAME, "context").build())
+        .addStatement(
+            "$1T hasRootComponent = ($1T) context.getApplicationContext()",
+            hasRootComponentInterface)
+        .addStatement(
+            "return (($T) (hasRootComponent.component())).make$T()",
+            hasComponenetInterface,
+            dialerComponentElement)
+        .returns(getComponentClass(typeBuilder, dialerComponentElement))
+        .build();
+  }
+
+  private void addElement(TypeSpec.Builder builder, Element element) {
+    switch (element.getKind()) {
+      case INTERFACE:
+        builder.addType(cloneInterface(MoreElements.asType(element), "").build());
+        break;
+      case CLASS:
+        builder.addType(cloneClass(MoreElements.asType(element), "").build());
+        break;
+      case FIELD:
+        builder.addField(cloneField(MoreElements.asVariable(element)).build());
+        break;
+      case METHOD:
+        builder.addMethod(cloneMethod(MoreElements.asExecutable(element)));
+        break;
+      case CONSTRUCTOR:
+        builder.addMethod(cloneConstructor(MoreElements.asExecutable(element)));
+        break;
+      default:
+        throw new RuntimeException(
+            String.format("Unexpected element %s met during class cloning phase!", element));
+    }
+  }
+
+  private MethodSpec cloneMethod(ExecutableElement element) {
+    return MethodSpec.methodBuilder(element.getSimpleName().toString())
+        .addModifiers(element.getModifiers())
+        .returns(TypeName.get(element.getReturnType()))
+        .addParameters(cloneParameters(element.getParameters()))
+        .build();
+  }
+
+  private MethodSpec cloneConstructor(ExecutableElement element) {
+    return MethodSpec.constructorBuilder()
+        .addModifiers(element.getModifiers())
+        .addParameters(cloneParameters(element.getParameters()))
+        .build();
+  }
+
+  private List<ParameterSpec> cloneParameters(
+      List<? extends VariableElement> variableElementsList) {
+    List<ParameterSpec> list = new ArrayList<>();
+    for (VariableElement variableElement : variableElementsList) {
+      ParameterSpec.Builder builder =
+          ParameterSpec.builder(
+                  TypeName.get(variableElement.asType()),
+                  variableElement.getSimpleName().toString())
+              .addModifiers(variableElement.getModifiers());
+      list.add(builder.build());
+    }
+    return list;
+  }
+
+  private TypeSpec.Builder cloneInterface(TypeElement element, String prefix) {
+    return cloneType(TypeSpec.interfaceBuilder(prefix + element.getSimpleName()), element);
+  }
+
+  private TypeSpec.Builder cloneClass(TypeElement element, String prefix) {
+    return cloneType(TypeSpec.classBuilder(prefix + element.getSimpleName()), element);
+  }
+
+  private FieldSpec.Builder cloneField(VariableElement element) {
+    FieldSpec.Builder builder =
+        FieldSpec.builder(TypeName.get(element.asType()), element.getSimpleName().toString());
+    element.getModifiers().forEach(builder::addModifiers);
+    return builder;
+  }
+
+  private TypeSpec.Builder cloneType(TypeSpec.Builder builder, TypeElement element) {
+    element.getModifiers().forEach(builder::addModifiers);
+    for (Element enclosedElement : element.getEnclosedElements()) {
+      addElement(builder, enclosedElement);
+    }
+    return builder;
+  }
+
+  private ClassName getComponentClass(
+      TypeSpec.Builder typeBuilder, TypeElement dialerComponentElement) {
+    return ClassName.get(getPackageName(dialerComponentElement), typeBuilder.build().name);
+  }
+
+  private String getPackageName(TypeElement element) {
+    return ClassName.get(element).packageName();
+  }
+}
diff --git a/java/com/android/dialer/rootcomponentgenerator/processor/MetadataGeneratingStep.java b/java/com/android/dialer/rootcomponentgenerator/processor/MetadataGeneratingStep.java
new file mode 100644
index 0000000..70ad1b2
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/processor/MetadataGeneratingStep.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.rootcomponentgenerator.processor;
+
+import static javax.tools.Diagnostic.Kind.ERROR;
+
+import com.android.dialer.rootcomponentgenerator.annotation.DialerComponent;
+import com.android.dialer.rootcomponentgenerator.annotation.InstallIn;
+import com.android.dialer.rootcomponentgenerator.annotation.RootComponentGeneratorMetadata;
+import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.TypeSpec;
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.Set;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.Element;
+
+/**
+ * Genereates metadata for every type annotated by {@link InstallIn} and {@link DialerComponent}.
+ *
+ * <p>The metadata has the information where the annotated types are and it is used by annotation
+ * processor when the processor tries to generate root component.
+ */
+final class MetadataGeneratingStep implements ProcessingStep {
+
+  private final ProcessingEnvironment processingEnv;
+
+  MetadataGeneratingStep(ProcessingEnvironment processingEnv) {
+    this.processingEnv = processingEnv;
+  }
+
+  @Override
+  public Set<? extends Class<? extends Annotation>> annotations() {
+    return ImmutableSet.of(DialerComponent.class, InstallIn.class);
+  }
+
+  @Override
+  public Set<? extends Element> process(
+      SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+
+    for (Element element : elementsByAnnotation.get(DialerComponent.class)) {
+      generateMetadataFor(DialerComponent.class, element);
+    }
+    for (Element element : elementsByAnnotation.get(InstallIn.class)) {
+      if (element.getAnnotation(InstallIn.class).variants().length == 0) {
+        processingEnv
+            .getMessager()
+            .printMessage(
+                ERROR, String.format("@InstallIn %s must have at least one variant", element));
+        continue;
+      }
+      generateMetadataFor(InstallIn.class, element);
+    }
+
+    return Collections.emptySet();
+  }
+
+  private void generateMetadataFor(
+      Class<? extends Annotation> annotation, Element annotatedElement) {
+    TypeSpec.Builder metadataClassBuilder =
+        TypeSpec.classBuilder(annotatedElement.getSimpleName() + "Metadata");
+    metadataClassBuilder.addAnnotation(
+        AnnotationSpec.builder(RootComponentGeneratorMetadata.class)
+            .addMember("tag", "$S", annotation.getSimpleName())
+            .addMember("annotatedClass", "$T.class", annotatedElement.asType())
+            .build());
+    TypeSpec metadataClass = metadataClassBuilder.build();
+    RootComponentUtils.writeJavaFile(
+        processingEnv, RootComponentUtils.METADATA_PACKAGE_NAME, metadataClass);
+  }
+}
diff --git a/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentGeneratingStep.java b/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentGeneratingStep.java
new file mode 100644
index 0000000..86a0308
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentGeneratingStep.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.rootcomponentgenerator.processor;
+
+import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
+import static com.google.auto.common.MoreElements.getAnnotationMirror;
+import static com.google.auto.common.MoreElements.isAnnotationPresent;
+
+import com.android.dialer.rootcomponentgenerator.annotation.DialerComponent;
+import com.android.dialer.rootcomponentgenerator.annotation.DialerRootComponent;
+import com.android.dialer.rootcomponentgenerator.annotation.DialerVariant;
+import com.android.dialer.rootcomponentgenerator.annotation.InstallIn;
+import com.android.dialer.rootcomponentgenerator.annotation.RootComponentGeneratorMetadata;
+import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep;
+import com.google.auto.common.MoreElements;
+import com.google.common.base.Optional;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.SetMultimap;
+import com.squareup.javapoet.AnnotationSpec;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.TypeSpec;
+import dagger.Component;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.inject.Singleton;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+
+/** Generates root component for a java type annotated with {@link DialerRootComponent}. */
+final class RootComponentGeneratingStep implements ProcessingStep {
+
+  private final ProcessingEnvironment processingEnv;
+
+  public RootComponentGeneratingStep(ProcessingEnvironment processingEnv) {
+    this.processingEnv = processingEnv;
+  }
+
+  @Override
+  public Set<? extends Class<? extends Annotation>> annotations() {
+    return ImmutableSet.of(DialerRootComponent.class);
+  }
+
+  @Override
+  public Set<? extends Element> process(
+      SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
+    for (Element element : elementsByAnnotation.get(DialerRootComponent.class)) {
+      generateRootComponent(MoreElements.asType(element));
+    }
+    return Collections.emptySet();
+  }
+
+  /**
+   * Generates a root component.
+   *
+   * @param rootElement the annotated type with {@link DialerRootComponent} used in annotation
+   *     processor.
+   */
+  private void generateRootComponent(TypeElement rootElement) {
+    DialerRootComponent dialerRootComponent = rootElement.getAnnotation(DialerRootComponent.class);
+    ListMultimap<DialerVariant, TypeElement> componentModuleMap = generateComponentModuleMap();
+    List<TypeElement> componentList = generateComponentList();
+    DialerVariant dialerVariant = dialerRootComponent.variant();
+    TypeSpec.Builder rootComponentClassBuilder =
+        TypeSpec.interfaceBuilder(dialerVariant.toString())
+            .addModifiers(Modifier.PUBLIC)
+            .addAnnotation(Singleton.class);
+    for (TypeElement componentWithSuperInterface : componentList) {
+      rootComponentClassBuilder.addSuperinterface(
+          ClassName.get(componentWithSuperInterface)
+              .peerClass(
+                  RootComponentUtils.GENERATED_COMPONENT_PREFIX
+                      + componentWithSuperInterface.getSimpleName())
+              .nestedClass("HasComponent"));
+    }
+    AnnotationSpec.Builder componentAnnotation = AnnotationSpec.builder(Component.class);
+    for (TypeElement annotatedElement : componentModuleMap.get(dialerVariant)) {
+      componentAnnotation.addMember("modules", "$T.class", annotatedElement.asType());
+    }
+    rootComponentClassBuilder.addAnnotation(componentAnnotation.build());
+    TypeSpec rootComponentClass = rootComponentClassBuilder.build();
+    RootComponentUtils.writeJavaFile(
+        processingEnv, ClassName.get(rootElement).packageName(), rootComponentClass);
+  }
+
+  private List<TypeElement> generateComponentList() {
+    List<TypeElement> list = new ArrayList<>();
+    extractInfoFromMetadata(DialerComponent.class, list::add);
+    return list;
+  }
+
+  private ListMultimap<DialerVariant, TypeElement> generateComponentModuleMap() {
+    ListMultimap<DialerVariant, TypeElement> map = ArrayListMultimap.create();
+    extractInfoFromMetadata(
+        InstallIn.class,
+        (annotatedElement) -> {
+          for (DialerVariant rootComponentName :
+              annotatedElement.getAnnotation(InstallIn.class).variants()) {
+            map.put(rootComponentName, annotatedElement);
+          }
+        });
+    return map;
+  }
+
+  private void extractInfoFromMetadata(
+      Class<? extends Annotation> annotation, MetadataProcessor metadataProcessor) {
+    PackageElement cachePackage =
+        processingEnv.getElementUtils().getPackageElement(RootComponentUtils.METADATA_PACKAGE_NAME);
+    for (Element element : cachePackage.getEnclosedElements()) {
+      Optional<AnnotationMirror> metadataAnnotation =
+          getAnnotationMirror(element, RootComponentGeneratorMetadata.class);
+      if (isAnnotationPresent(element, RootComponentGeneratorMetadata.class)
+          && getAnnotationValue(metadataAnnotation.get(), "tag")
+              .getValue()
+              .equals(annotation.getSimpleName())) {
+        TypeMirror annotatedClass =
+            (TypeMirror) getAnnotationValue(metadataAnnotation.get(), "annotatedClass").getValue();
+        TypeElement annotatedElement =
+            processingEnv.getElementUtils().getTypeElement(annotatedClass.toString());
+        metadataProcessor.process(annotatedElement);
+      }
+    }
+  }
+
+  private interface MetadataProcessor {
+    void process(TypeElement typeElement);
+  }
+}
diff --git a/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentProcessor.java b/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentProcessor.java
new file mode 100644
index 0000000..5e083d2
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentProcessor.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.rootcomponentgenerator.processor;
+
+import com.google.auto.common.BasicAnnotationProcessor;
+import com.google.auto.service.AutoService;
+import com.google.common.collect.ImmutableList;
+import javax.annotation.processing.Processor;
+import javax.lang.model.SourceVersion;
+
+/** Processes annotations defined by RootComponentGenerator. */
+@AutoService(Processor.class)
+public class RootComponentProcessor extends BasicAnnotationProcessor {
+
+  @Override
+  protected Iterable<? extends ProcessingStep> initSteps() {
+    return ImmutableList.of(
+        new ComponentGeneratingStep(processingEnv),
+        new MetadataGeneratingStep(processingEnv),
+        new RootComponentGeneratingStep(processingEnv));
+  }
+
+  @Override
+  public SourceVersion getSupportedSourceVersion() {
+    return SourceVersion.latestSupported();
+  }
+}
diff --git a/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentUtils.java b/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentUtils.java
new file mode 100644
index 0000000..8892971
--- /dev/null
+++ b/java/com/android/dialer/rootcomponentgenerator/processor/RootComponentUtils.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.rootcomponentgenerator.processor;
+
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.TypeSpec;
+import java.io.IOException;
+import javax.annotation.processing.ProcessingEnvironment;
+
+/**
+ * Contains a basic method writing java file to a curtain package. ProcessingEnvironment is needed.
+ */
+public abstract class RootComponentUtils {
+  /**
+   * The place where the generator puts metadata files storing reference for {@link
+   * RootComponentGeneratingStep}.
+   */
+  static final String METADATA_PACKAGE_NAME = "com.android.dialer.rootcomponentgenerator.metadata";
+
+  static final String GENERATED_COMPONENT_PREFIX = "Gen";
+
+  static void writeJavaFile(
+      ProcessingEnvironment processingEnv, String packageName, TypeSpec typeSpec) {
+    try {
+      JavaFile.builder(packageName, typeSpec)
+          .skipJavaLangImports(true)
+          .build()
+          .writeTo(processingEnv.getFiler());
+    } catch (IOException e) {
+      System.out.println(e);
+      throw new RuntimeException(e);
+    }
+  }
+}