Android manual setup and instrumentation

Getting Started

Do the following to setup Android apps for instrumentation:

Manual instrumentation features

Manual instrumentation provides visibility into:

Crash reporting

Crash reporting is disabled by default. Call the Dynatrace.enableCrashReporting method to enable or disable crash reporting.

Disabling crash reporting ignores the corresponding value from your user experience configuration.

Enabling crash reporting captures all unhandled exceptions and errors and sends a crash report immediately to the server. The Android crash report includes the occurrence time and the full stack trace of the exception. If the crash occurs while a lifecycle action is active, the mobile agent attaches the crash report to the lifecycle action.

Lifecycle instrumentation

By default, lifecycle data collection is on. You can turn it off in the user experience configuration file.

Complete the following tasks to enable lifecycle data capturing:

You can also use Auto-Instrumentation for Android to automatically perform this instrumentation.

Collected lifecycle data

With lifecycle instrumentation, the mobile agent automatically collects the following data and renders it as actions:

  • Application Start Event: Represents the time from Application.onCreate() to Activity.onPostResume() of the first activity displayed. If the first activity does not extend a Dynatrace activity, the application-start event time is not recorded correctly.
  • Activity Display: Represents the time from Activity.onCreate() to Activity.onPostResume().
  • Activity Redisplay: Represents the time from Activity.onStart() to Activity.onPostResume().

These activities' display/redisplay actions can also contain web requests or crash events.

User action monitoring

Create user actions with the Dynatrace.enterAction method and close them with the leaveAction method. The resulting action is visible as a mobile user action PurePath in the AppMon client. For example, you can use the enterAction and leaveAction methods to determine how long it takes to pull content from a remote server. You get visibility to the corresponding backend transactions within the action scope. Other event types (reportEvent, reportValue and reportError) can be reported within the context of the action object, thus creating a series of events within an action scope.

The reportError event is different from the reportValue event in that it is specifically identified as an error type of event. The integer value most likely contains an error code. You can also use the Dynatrace.reportError method to create a stand-alone error action.

Note

When the parent action is closed, the mobile agent automatically closes all nested/child actions of the parent action. The mobile agent discards the captured action data (including child actions), when the action is not closed.

Web request monitoring

Web request monitoring is supported for the Apache HttpClient and HttpURLConnection HTTP frameworks. For all other HTTP frameworks, ensure that the Dynatrace mobile tag is placed on the HTTP request.

Web request tagging

Web request tagging lets the AppMon server identify mobile traffic and correlates web request server-side PurePath data to a corresponding mobile user action. To do this, the mobile agent must add an additional HTTP header to your web request. The web server agent analyzes this HTTP header and the AppMon server generates a corresponding web request PurePath. No web request PurePath is generated for web requests to unmonitored servers such as third party servers.

There are two ways to assign a web request to an action.

  • Use the DTXAction.tagRequest methods of a specific action to assign a web request to this action.
  • Use the Dynatrace.tagRequest methods to let the mobile agent assign the web requests to an appropriate user action.

The mobile agent uses the following rule set:

  • If the current thread has an open action, when the request is tagged, then the mobile agent assigns the web request to the open action.
  • If the current thread has no open action, the AppMon server assigns the web request to an action that calls its leaveAction() method in the same thread where the tagging is done. The tagging time must fall between the action enter and leave times.
  • If neither of the preceding cases applies, the web request is not assigned to any action. In this case, the server-side PurePath data is not linked to a mobile user action, but PurePath data can be identified as mobile traffic in the transaction flow.

The tagRequest(java.net.HttpURLConnection) and tagRequest(org.apache.http.HttpRequest) methods generate and add the correct HTTP header to your web request automatically.

DTXAction action = Dynatrace.enterAction("<action_name>");
URL url = new URL("http://myhost.mydomain.com/example");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
action.tagRequest(connection);

// handle web request

action.leaveAction();
DTXAction action = Dynatrace.enterAction("<action_name>");
HttpGet get = new HttpGet("http://myhost.mydomain.com/example");
action.tagRequest(get);

// handle web request

action.leaveAction();

For the Apache HttpClient library, you can also use the Dynatrace.registerRequestTaggingInterceptor(org.apache.http.impl.client.DefaultHttpClient) method. This method adds the additional HTTP header to all requests executed with the given DefaultHttpClient. The interceptor overwrites any existing tag placed on the request.

For third party libraries, you must use the getRequestTag() general method to generate the correct tag value. You must manually add the needed HTTP header to your web request. Use the Dynatrace.getRequestTagHeader() method to get the header key, as shown below for the OkHttp 3 library.

DTXAction action = Dynatrace.enterAction("<action_name>");
Request request = new Request.Builder()
		.url("http://myhost.mydomain.com/example")
                .addHeader(Dynatrace.getRequestTagHeader(), action.getRequestTag())
                .build();

// handle web request

action.leaveAction();
Note

Web request tagging does not measure network contribution time. The generated web request PurePath only contains the timing values from the server agent. You must use web request timing for full visibility.

Web request timing

Web request timing is an extension of web request tagging. It lets you monitor the web request on the mobile side. It also monitors web requests to unmonitored servers.

You must use web request tagging and create manual timings by using the WebRequestTiming class. The Dynatrace.getWebRequestTiming(java.net.HttpURLConnection) and Dynatrace.getWebRequestTiming(org.apache.http.HttpRequest) methods tag your web request (like the Dynatrace.tagRequest methods) and provide the corresponding WebRequestTiming object. For third party libraries, you must use the general method Dynatrace.getWebRequestTiming(String) and generate the parameter value with the Dynatrace.getRequestTag() method. You must manually add the needed HTTP header to your web request.

Call the startWebRequestTiming method before the web request is sent to the server. Call the stopWebRequestTiming method after receiving and reading the HTTP response. The mobile agent generates a web request action with measured timing values and the AppMon server appends the server PurePath data to this web request action. You can see network timings in the Network Contribution column of the User Actions PurePath dashlet and other dashlets.

Examples

Difference between tagging and timing

When you use web request tagging, the AppMon server generates the corresponding mobile web request PurePath. The timing values are based on the server-side timing values. As shown below, the timing values of the mobile web request don't fit the mobile user action search request. This is because the mobile devices' system clocks differ from the server clock. The mobile agent tries to minimize this offset and provides timing values based on the server time.

Example with web request tagging
Example with web request tagging

When you use web request timing, the mobile agent generates a mobile web request event and sends the data to the AppMon server. The AppMon Server links the PurePath data from the mobile and Server agent. This approach lets you measure the network contribution time and shows the correct time values for mobile nodes in the user action PurePath dashlet. Unfortunately the server node may differ from the mobile nodes because of the system clock difference, as shown below.

Example with web request timing
Example with web request timing

Advanced settings

Use the class AppMonConfigurationBuilder to customize all advanced agent settings with different API methods.

new AppMonConfigurationBuilder("YourAppId", "https://www.example.com")
	.withHybridMonitoring(true)
	.withMonitoredDomains("https://www.foo.com", "https://www.bla.com")
	.buildConfiguration();

Instead of the API methods you can also specify some advanced settings within a property file. The default name for the property file is Dynatrace.properties and can be loaded with the method loadDefaultProperties(Context).

Dynatrace.startup(this, new AppMonConfigurationBuilder("YourAppId", "https://www.example.com")
	.loadDefaultProperties(context)
	.buildConfiguration());

The following table shows the available advanced configuration settings, that can be specified via a properties file or the loadProperties methods.

Key Type Default Description
DTXAllowAnyCert boolean false Defines the certificate policy. If set to true, all certificates are accepted. If set to false, valid certificates from known certificate authorities are accepted. You can still use self-signed certificates (see DTXBKSFileName), they are checked for validity.
DTXBKSFileName string This key (no file extension) defines the name of a BKS keystore file which contains a self-signed certificate and is used as an additional anchor to validate HTTPS communication. It is needed if DTXAllowAnyCert is false and a self-signed certificate is used on the server. The BKS Keystore file must be in the APKs raw directory.
DTXBKSPassword string The password for the BKS keystore file (see DTXBKSFileName).
DTXMonitorCookie string The given value is automatically added as a cookie to the HTTP requests of the Agent—Server communication, so they can pass your infrastructure's requirements.
DTXSetCookiesForDomain string To be able to use JavaScript Agent or JavaScript bridge, you need to set cookies for each instrumented domain or server, communicating with your application. Specify these domains and servers here.

You can specify domains, hosts, or IP addresses. Domains or sub-domains must start with a dot. Separate the list elements with a comma.
DTXHybridApplication boolean false Hybrid application flag. Set the value to true for hybrid applications.
DTXLogLevel string Defines the log level. Debug logs can be activated with the value debug.
DTXUserOptIn boolean false Defines if the privacy settings for data collection and crash reporting can be changed via the agent API.
Note

If you use a combination of manual and auto-instrumentation, the auto-instrumentor injects a Dynatrace.startup call into the Application.onCreate method. In this case you will lose your manual configuration, because the Dynatrace.startup call from the auto-instrumentor is called before your Dynatrace.startup call.

The property DTXAutoStart allows you to deactivate the auto-start feature from the auto-instrumentation. Then you can define a manual Dynatrace.startup call in the Application.onCreate method. In this case you can't use the Dynatrace.properties file for customizing the configuration, because it will be used by the auto-instrumentor to configure the agent correctly. Therefore, it is important that you call the loadDefaultProperties(Context) method for your AppMonConfigurationBuilder. If you omit this step, the auto-instrumentation features will not work properly.

Custom HTTP headers

If the HTTP requests of the Agent do not fulfil the security requirements of your server infrastructure, you can modify the HTTP headers of the Agent with the Dynatrace.setBeaconHeaders(Map<String, String>) method. This feature allows you to add an Authorization header to the HTTP requests and immediately reconnect to the instrumented web or application server, when the token has expired. To delete the old headers call Dynatrace.setBeaconHeaders(null) method.

Basic Authorization

When the authorization information is already available at the app start, you should call the Dynatrace.setBeaconHeaders method before the startup Dynatrace.startup method. Then it is guaranteed that every HTTP request of the Agent has the correct headers.

Map<String, String> headers = new HashMap<>();
headers.put("Cookie", "n1=v1; n2=v2");
headers.put("MyHeader", "myValue");
headers.put("Authorization", basicAuthorization(username, password));
Dynatrace.setBeaconHeaders(headers);

Dynatrace.startup(this, new AppMonConfigurationBuilder("YourAppId", "https://www.example.com")
	.buildConfiguration());

When the authorization information is not available at the app start, you should call the Dynatrace.setBeaconHeaders method, when the information is available. The startup Dynatrace.startup method should still be called in the Application.onCreate method to track the correct start time. The Agent will be automatically deactivated, when the server sends an invalid status code response. The Dynatrace.setBeaconHeaders method will activate the Agent and it will immediately reconnect to the instrumented web or application server.

Authorization with a token

If you use an authorization procedure, which requires you to regularly update a token, then you should add a CommunicationProblemListener. The listener must be added via the AppMonConfigurationBuilder in the Dynatrace.startup method.

Dynatrace.startup(this, new AppMonConfigurationBuilder("YourAppId", "http://myhost.mydomain.com")
	.withCommunicationProblemListener(new MyDynatraceListener())
	.buildConfiguration());

When you use a CommunicationProblemListener, the Agent communication behavior is slightly different from the normal behavior. If the instrumented web or application server reacts with an invalid status code, like 403 Forbidden, the Agent will not reconnect to the server. Instead the Agent will wait until you have specified the correct headers with the method Dynatrace.setBeaconHeaders. In this case the Agent will notify the CommunicationProblemListener asynchronously in a background thread via the onFailure(int, String, String) interface method. The following code snippet show a sample implementation for the CommunicationProblemListener interface:

public class MyDynatraceListener implements CommunicationProblemListener{

	@Override
	public void onFailure(int responseCode, String responseMessage, String body) {
		String token = refreshToken();
		Dynatrace.setBeaconHeaders(generateAuthorizationHeader(token));
	}

	@Override
	public void onError(Throwable throwable) {
		//do nothing
	}
}

The interface method onError(Throwable) is asynchronously called, when a communication problem occurred, for example connection timeout, SSL handshake errors. In this case the Agent will wait for certain time and then reconnects to the instrumented web or application server. Normally you do not have to react on this callback method.

Data privacy (user opt-in mode)

As of version 7.1.4, the Mobile Agent enables you to dynamically adjust data-privacy settings so that you can build your apps in compliance with GDPR data-privacy regulations. To activate this feature, enable the user opt-in mode:

Dynatrace.startup(this, new AppMonConfigurationBuilder("YourAppId", "http://myhost.mydomain.com")
	.withUserOptIn(true)
	.withCrashReporting(true)
	.buildConfiguration());
Note

The Dynatrace.enableCrashReporting(boolean) method is deprecated. You should enable crash reporting with the ConfigurationBuilder.withCrashReporting(boolean) method instead.

The privacy API methods allow you to dynamically activate/deactivate crash reporting and to change the data-collection level based on the individual preferences of your end users. Each end user can select from three data-privacy levels:

  • off: AppMon doesn't capture any monitoring data.
  • performance: AppMon will only captures anonymous performance data. Monitoring data that can be used to identify individual users (for example, user tags or custom values), is not captured.
  • user behavior: AppMon captured both performance and user data. In this mode AppMon recognizes and reports on users who re-visit in future sessions.

When the mobile agent starts for the first time, it deactivates crash reporting and sets the data-collection level to off. You should change the privacy settings (based on each user's individual preference), when your app starts the first time. The mobile agent does not provide a privacy settings dialog or similar UI component. You must integrate a privacy dialog into your app. We recommend that you display the privacy dialog before your app is displayed and then apply the user's privacy preference. You should also enable your users to change their privacy settings in the future.

The mobile agent persists the privacy setting and automatically applies it when the app is restarted. Each time the user changes the data-collection level a new session with the new privacy settings will be generated by the mobile agent. Do not wrap this API method with a user action. Otherwise, {the mobile agent can't attach the user action to the correct session.

With the Dynatrace.setCrashReportingOptedIn(boolean) method you can activate or deactivate crash reporting. The data collection level can be changed with the Dynatrace.setDataCollectionLevel(DataCollectionLevel) method. You can retrieve the privacy settings with the Dynatrace.getDataCollectionLevel and Dynatrace.isCrashReportingOptedIn methods. But you can't use the privacy API methods before Mobile Agent is started. Otherwise Mobile Agent will throw an exception.

ProGuard settings

ProGuard is a free Java class file shrinker, optimizer, obfuscator, and preverifier. It detects and removes unused classes, fields, methods, and attributes.

The AAR file contains the required rule set to exclude the Agent library from obfuscation and optimization. No manual configuration needed.

Limitations and Overhead

  • For Android 4.4 and earlier, the agent can't detect the correct foreground or background application state unless all activity classes are instrumented. You also have to add the GET_TASKS permission.
  • The agent does not contain a specific web request tagging and timing API for third party web request frameworks. You have to use the general API methods (like Dynatrace.getWebRequestTiming(String)).
  • There is limited support for multi-process applications, as each process starts its own agent and has its own session number.
  • Adding the Android mobile agent (whether manually or through auto-instrumentation) to an application increases the size of the application by about 100 KB to 200 KB. The size increase depends on the implementation of your application and how effectively Android can store the mobile agent and the instrumentation code in your .dex files.

The impacts on app performance and mobile data usage are summarized in the general overhead section.