Adjust communication with OneAgent SDK for Android

After instrumentation is complete, check the following aspects regarding communication with OneAgent.

Network security configuration

If your Android app has network security configured, ensure that the HTTP traffic to the beaconUrl endpoint is not blocked by the network security configuration.

Firewall

Ensure that the GET and POST requests to the beaconUrl endpoint are not blocked by a firewall.

Include certificates

For the HTTPS communication, OneAgent verifies the server certificate and the host name. OneAgent communication fails when the verification steps aren't successfully completed.

If your Cluster ActiveGate doesn't have a certificate that is issued by a trusted intermediate or root CA, you must provide a certificate for SSL communication. This can be done by either providing the server certificate in the network security configuration (for Android Target SDK 24 or later) or by including the certificate you are using into a KeyStore file and providing it to OneAgent by performing a manual startup via the DESKConfigurationBuilder API.

Network security configuration

If you want to use the network security configuration feature, add a domain-config section to your network-security-config XML.

For example:

<domain-config>
	<domain includeSubdomains="true">your.domain.com</domain>
	<trust-anchors>
		<certificates src="@raw/your_server_certificate" />
	</trust-anchors>
</domain-config>

KeyStore object via ConfigurationBuilder

If you want to support Android API levels below 24 or don't want to use the network security configuration feature, provide a KeyStore object. This object must hold the certificate chain of the Cluster ActiveGate that you want to connect to.

For example:

KeyStore trusted = KeyStore.getInstance("BKS");
try (InputStream in = getResources().openRawResource(R.raw.mykeystore)) {
    trusted.load(in, "myverysecretpassword".toCharArray());
}
DESK.startup(this, new DESKConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>")
    .withKeyStore(trusted)
    .buildConfiguration());

Note: If you're using BouncyCastle as your keystore instance, ensure that the keystore is generated with BouncyCastle 1.45. The BouncyCastle 1.46 file format is not compatible with older versions of Android. For more details see Android AOSP issue.

Also note that if you define both, network security configuration and a keystore, the keystore takes precedence.

Deactivate certificate validation

You can also deactivate the certificate validation. Use this option with caution and not in production code as it dismantles the connection authenticity. Hostname verification can't be deactivated.

  • via DESK Android Gradle plugin

You can deactivate the certificate validation via the certificateValidation property.

desk {
    configurations {
        sampleConfig {
            debug {
                certificateValidation false
            }
        }
    }
}
  • via OneAgent SDK

You can also deactivate the certificate validation with the ConfigurationBuilder.withCertificateValidation(boolean) method.

DESK.startup(this, new DESKConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>")
	.withCertificateValidation(false)
	.buildConfiguration());

Certificate pinning

To use certificate pinning, see the instructions provided by Android at network security configuration - Certificate pinning.

Custom HTTP headers

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

Basic authorization

When the authorization information is already available at the app start, call the DESK.setBeaconHeaders method before the starting up DESK.startup method. Every HTTP request of the OneAgent will then have the correct headers.

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

DESK.startup(this, new DESKConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>")
	.buildConfiguration());

If the authorization information is not available at the app start, call the DESK.setBeaconHeaders method when the information is available. The startup DESK.startup method should still be called in the Application.onCreate method to track the correct start time. OneAgent will be automatically deactivated when the server sends an invalid status code response. The DESK.setBeaconHeaders method will activate OneAgent and will immediately reconnect to the Cluster ActiveGate.

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 DESKConfigurationBuilder in the DESK.startup method.

DESK.startup(this, new DESKConfigurationBuilder("<YourApplicationID>", "<ProvidedBeaconURL>")
	.withCommunicationProblemListener(new YourDESKListener())
	.buildConfiguration());

When you use a CommunicationProblemListener, OneAgent communication behavior is slightly different from the normal behavior. If the Cluster ActiveGate reacts with an invalid status code, like 403 Forbidden, OneAgent won't reconnect to the server. Instead, OneAgent will wait until you have specified the correct headers with the method DESK.setBeaconHeaders. In this case, OneAgent will notify the CommunicationProblemListener asynchronously in a background thread via the onFailure(int, String, String) interface method. The following code snippet shows a sample implementation for the CommunicationProblemListener interface:

public class YourDESKListener implements CommunicationProblemListener {

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

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

The interface method onError(Throwable) is asynchronously called when a communication problem occurs, such as a connection timeout or an SSL handshake error. In this case, OneAgent waits for a certain time and then reconnects to the Cluster ActiveGate. Normally you don't have to react on this callback method.

Offline monitoring

For efficiency, DESK does not accept monitoring data older than 10 minutes. If the app is not connected to the internet for a longer time period, OneAgent discards the old monitoring data and stops monitoring the app until the device establishes a new network connection.