Skip to content
/ gretel Public

Gretel - Gradle plugin that adds trace events to an Android app

License

Notifications You must be signed in to change notification settings

awenger/gretel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gretel

Gretel is a Gradle plugin that instruments Android artifacts by adding system trace events during compilation.

Gretel enables the tracing of third-party and dynamically generated code, such as Dagger or Hilt. Adding traces at compile time also keeps the logic of the app focused. Centralized management of system traces also allows toggling the tracing on and off for the entire application. Gretel offers a flexible way to target specific sections of an Android artifact for tracing. For example, it is possible to add traces to all lifecycle callback methods, like onCreate and onResume, of all Activities with a single instruction.

How to

  • Apply the gretel gradle plugin, see section Setup
  • Specify the methods you want to be traced, see section Configuration
  • Capture a system trace on the device, see here
  • Perform the action in the app that you want to trace, for example launch the app
  • Stop the system trace capture
  • Pull the traces from the device via adb pull /data/local/traces/ .
  • Inspect the trace in Android studio (drag the trace file onto the bar of open files or open the Profiler tab and select + > Load from file...)

Setup

plugins {
    id("de.awenger.gretel") version "0.5.0"
}

Configuration

Gretel doesn't add any traces out of the box. It provides a DSL that configures to which classes and methods gretel will add system traces at compile time. For example the following snipped will make gretel add a trace to the onCreate method of the your.app.MainActivity class and the onCreateView method of the your.app.MainFragment class. The trace will be named MainActivity::onCreate and your.app.MainFragment::onCreateView

android {
  gretel {
    traces = listOf(
      defineTrace {
        classes = classes(type("your.app", "MainActivity"))
        methods = listOf(method("onCreate"))
      },
      defineTrace {
        classes = classes(type("your.app", "MainFragment"))
        methods = listOf(method("onCreateView"))
      }
    )
  }
}

It is possible to omit any of these parameters to target multiple classes or methods. For example the following snipped will add a trace to all methods of all classes in the package com.example.app.activites.

defineTrace {
  classes = classes(superType = type("com.example.app.activites"))
}

Classes can also be targeted for tracing by the interfaces they implement or the class they extend. For example the following snipped will add traces to the onCreate and onResume methods of all classes that extend android.app.Activity.

defineTrace {
  classes = classes(superType = type("android.app", "Activity"))
  methods = listOf(
    method("onCreate"),
    method("onResume")
  )
}

Classes can also be targeted via annotations on the class. However, only annotation with RetentionPolicy(CLASS) and RetentionPolicy(RUNTIME) are supported. Annotations with @Retention(SOURCE) are not supported because they are already removed at compile time when gretel adds traces. The following snipped adds traces to all methods of classes that are annotated with @dagger.hilt.android.lifecycle.HiltViewModel:

defineTrace {
  classes = classes(annotationType = type("dagger.hilt.android.lifecycle", "HiltViewModel"))
}

Why gretel

  • Adding traces at compile time, configured in a separate file, keeps the app code focused on the functionality.
  • Gretel can add traces to third-party code or code that is generated at compile time. For example gretel can add traces to the code that is generated by Hilt or Dagger.
  • Powerful targeting that enables adding traces to multiple classes and methods with a single definition. For example gretel can add traces to all lifecycle methods of all Activities in an app with a single definition.
  • The centralized definition of the traces makes it trivial to turn on/off the tracing for the whole app.

Common use cases

The following sections showcase common use cases that add traces to specific functionality with gretel

Trace Android Application, BroadcastReceiver, Activity and Fragment

The following snipped will add traces to all methods in classes that extend (directly or indirectly) android.app.Application, android.content.BroadcastReceiver, android.app.Activity or androidx.fragment.app.Fragment. This can be used to trace the lifecycle callbacks in these classes.

gretel {
  traces = listOf(
    defineTrace {
      classes = classes(superType = type("android.app", "Application"))
    },
    defineTrace {
      classes = classes(superType = type("android.content", "BroadcastReceiver"))
    },
    defineTrace {
      classes = classes(superType = type("android.app", "Activity"))
    },
    defineTrace {
      classes = classes(superType = type("androidx.fragment.app", "Fragment"))
    }
  )
}

Dagger

Dagger/Hilt generates various classes to facilitate the dependency injection. It is impossible to modify such third party or generated code, so traces can not be added in the traditional way. Gretel can add traces to these classes and methods at compile time

gretel {
  traces = listOf(
    defineTrace {
      classes = classes(superType = type("dagger.internal", "Factory"))
      methods = listOf(method("get"))
    },
    defineTrace {
      classes = classes(superType = type("dagger", "MembersInjector"))
    },
    defineTrace {
      classes = classes(superType = type("dagger.android", "AndroidInjector"))
    }
  )
}

Traces

The gretel plugin adds the traces at app build time. The traces will be recorded via androidx.core.os.TraceCompat, by adding calls to TraceCompat::beginSection and TraceCompat::endSection to methods that are configured, see #Configuration

About

Gretel - Gradle plugin that adds trace events to an Android app

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages