Android Studioがapkのビルドとインストールするコード追ってみたメモ

# きっかけ
ビルド終わったあとに処理を差し込むプラグイン作りたいです。apkの前回との差分をチェックするみたいなプラグインが作りたいです。(誰かスマートなやり方を知っていたら教えて下さい。)
Android Studioのビルドを追えばきっとその近いところまでいけるはずです。

読み違えているところなどあればご指摘お願いします。


# 調べてみる
Android Studioが利用している、Android関連の実装が入っているAndroid Pluginのソースコードはどうやらここにおいてあるようです(http://tools.android.com/build/studio より)
https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev


ここに公式のAndroid Studioが実行するまでの流れなどのドキュメントが置いてあります。
このドキュメントを見ながら読んでみました。
https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/com/android/tools/idea/run/README.md


# Android Applicationの設定が追加されるまで

Android Pluginのplugin.xml(AndroidManifestみたいなもの)がこれになります。
https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/META-INF/plugin.xml

plugin.xmlで宣言されているconfigurationTypeが以下になります。

```xml
    <configurationType implementation="com.android.tools.idea.run.AndroidRunConfigurationType"/>
    <configurationType implementation="com.android.tools.idea.run.testing.AndroidTestRunConfigurationType"/>
```

ConfigrationTypeとはこの"Android Application"と"Android Tests"のことです。

![image](https://qiita-image-store.s3.amazonaws.com/0/27388/0f28f7df-6388-c89e-c11c-ecfc685a028b.png)

http://www.jetbrains.org/intellij/sdk/docs/basics/run_configurations/run_configuration_management.html より

com.android.tools.idea.run.AndroidRunConfigurationTypeクラスが以下になります。
https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/com/android/tools/idea/run/AndroidRunConfigurationType.java
AndroidRunConfigurationFactoryより`new AndroidRunConfiguration(project, this);`され、AndroidRunConfigurationが利用されます。

AndroidRunConfigurationクラスが以下になります。
https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/com/android/tools/idea/run/AndroidRunConfiguration.java


# ビルドされるまで

この記述がplugin.xmlにあるこれが端末にインストールされたり、起動される前に実行される。
ここでビルドを行う。

```xml
<stepsBeforeRunProvider implementation="com.android.tools.idea.gradle.run.MakeBeforeRunTaskProvider" />
```

MakeBeforeRunTaskProviderで以下のようにGradleTaskRunnerを呼び出す。createBuilder()してbuilderを作る。

```java
    BeforeRunBuilder builder =
      createBuilder(env, getModules(myProject, context, configuration), configuration, runConfigContext, task.getGoal());
    try {
      boolean success = builder.build(GradleTaskRunner.newRunner(myProject), cmdLineArgs);
      LOG.info("Gradle invocation complete, success = " + success);
      return success;
    }
```
https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/com/android/tools/idea/gradle/run/MakeBeforeRunTaskProvider.java#247


createBuilder()で作ったのはこういう感じで、BuildMode.ASSEMBLEなどが入っている。

```java
 return new DefaultGradleBuilder(gradleTasksProvider.getTasksFor(BuildMode.ASSEMBLE, testCompileType), BuildMode.ASSEMBLE);
```
https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/com/android/tools/idea/gradle/run/MakeBeforeRunTaskProvider.java#340


GradleTaskRunnerでGradleInvokerが実行される。

```java
          gradleInvoker.addAfterGradleInvocationTask(afterTask);
          gradleInvoker.executeTasks(tasks, buildMode, args);
```

https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/com/android/tools/idea/gradle/run/GradleTaskRunner.java#46

あとはInvokerでよしなにGradleタスクを作って実行しているみたい。


**stepsBeforeRunProviderに代わりに自分の実装を差し込むと、Google Compute Engineでビルドさせるなどビルドの部分だけ差し替えができるみたい。(すごい)**
https://github.com/nonylene/GradleExternalBuildPlugin


# 起動されるまで
先ほど書いたAndroidRunConfigurationBaseはgetStateを継承していて、Android Studio側からgetStateが呼ばれるので、AndroidRunStateを返す。

https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/com/android/tools/idea/run/AndroidRunConfigurationBase.java#310

AndroidRunStateではexecute()が実行され、AndroidLaunchTasksProviderを使ってLaunchTaskを取得します。
https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/com/android/tools/idea/run/AndroidRunState.java#68

AndroidLaunchTasksProviderではDeployApkTaskを返します。

```java
    return new DeployApkTask(myFacet, myLaunchOptions, myApkProvider, instantRunAware);
```

https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/com/android/tools/idea/run/AndroidLaunchTasksProvider.java#177

DeployApkTaskではアップロードやインストールを行う

```java

      String pkgName = apk.getApplicationId();
      if (!installer.uploadAndInstallApk(device, pkgName, apk.getFile(), launchStatus)) {
        return false;
      }
```

https://android.googlesource.com/platform/tools/adt/idea/+/studio-master-dev/android/src/com/android/tools/idea/run/tasks/DeployApkTask.java#89


# まとめ
読めなくはなかったです。
stepsBeforeRunProviderで自分で差し替えるハックはすごい。
ビルド終わったあとに処理を差し込みたいが、`stepsBeforeRunProvider`のafter版みたいな奴はなかったので、どうしたものか、、