📜 ⬆️ ⬇️

Networking in Android: traffic, security, and battery

Today, there are more than 800 thousand applications on Google Play. Many of them are based on client-server communication. When developing such applications, it is necessary to take into account three main points that will be discussed in this article.

What you need to remember when implementing the network part of the application

The first is traffic. It is not always possible to work on a free Wi-Fi connection, and the mobile Internet is still expensive, and this must be remembered, because traffic is the user's money.
')
The second is the battery limit. Mobile devices are necessary for the user for some daily affairs, meetings, walks, business, and when the battery sits down at the most inopportune moment, the user is indignant.
The third is security. Since we are still talking about mobile clients, and the data is walking across the network from client to server and back, they need to be protected.

Networking Implementation Approaches

To begin, let us recall what ways of implementing client-server communication exist and are popular today.
The first approach is based on sockets (here I mean working directly with the Socket API). It is often used in applications where the speed of message delivery is important, the order of message delivery is important, and you need to keep a stable connection to the server. This method is often implemented in messengers and games.



The second approach is frequent polling (polling): the client sends a request to the server and tells him: “Give me fresh data”; the server responds to the client's request and gives everything that it has accumulated by that moment.



The disadvantage of this approach is that the client does not know whether fresh data has appeared on the server. The network once again chases traffic, primarily because of the frequent connections to the server.

The third approach - long polling (long polling) - is that the client sends a "pending" request to the server. The server is looking to see if there is fresh data for the client, if they are not there, then it keeps the connection with the client until this data appears. As soon as the data appeared, he "pushes" them back to the client. The client, having received data from the server, immediately sends the next "pending" request, etc.



The implementation of this approach is quite complicated on a mobile client primarily due to the instability of the mobile connection. But with this approach, the traffic is consumed less than with the usual polling, since reduced the number of connections to the server.
The mechanism of long polling, or push notifications (push notifications), is implemented in the Android platform itself. And, probably, for most tasks it will be better to use it, rather than implement it yourself. Your app is signed by Google Cloud Messaging (GCM) to receive push notifications.



Thus, the connection is broken directly between the server and the client due to the fact that the server works with the GCM service and sends fresh data always to this service, and it in turn implements all the logic of delivering this data to your application. The advantages of this approach are that it eliminates the need for frequent connections to the server, because you know for sure that the data has appeared, and the GCM service notifies you of this.
Of these four approaches, push notifications and frequent surveys are the most popular in developing business applications. When implementing these approaches, we somehow have to establish a connection to the server and transfer data. Next, we will discuss the tools that are available to the developer to work on HTTP / HTTPS protocols.

HttpUrlConnection and HttpClient

In the arsenal of the Android developer, there are two classes for working on these protocols. The first is java.net.HttpURLConnection, the second is org.apache.http.client.HttpClient. Both of these libraries are included in the Android SDK. Further, the main points that will affect traffic, battery and safety when working with each of these libraries will be discussed in detail.

With HttpURLConnection, everything is simple. One class and all. This is explained by the fact that the parent class URLConnection was designed to work not only via the HTTP protocol, but also through such as file, mailto, ftp, etc.



HttpClient is designed more object oriented. It has a clear separation of abstractions. In the simplest case, we will work with five different interfaces: HttpRequest, HttpResponse, HttpEntity and HttpContext. Therefore, the Apache client is much heavier than the HttpUrlConnection.



As a rule, there is only one instance of the HttpClient class for the entire application. This is due to its heaviness. Using a separate instance for each request will be wasteful. We can, for example, store an instance of an HTTP client as a successor to the Application class.



In the case of HttpUrlConnection, a new client instance should be created for each request.



What makes the traffic?

During the operation of our application, the picture will be something like this.



The number and frequency of requests will depend on the functionality and saturation of the UI - application interface. Each such request establishes a TCP connection to the server. In this case, the traffic that will be spent will be equal to the sum of the connection settings and the sum of the transmitted data. In this case, it is possible to reduce traffic consumption by using a long-lived connection (keep alive).



The main idea of ​​keep alive connection is to use the same TCP connection for sending and receiving HTTP requests. The main benefits are reduced traffic and query execution time. I did a simple test, which consisted in the sequential execution of 10 requests for the same host. Data is presented in the table below. When keep alive is off, you can see that the average query execution time was about two seconds. In the case of keep alive, this time decreased to 1.7 seconds, which is 16% faster. This is primarily due to the fact that eliminating the need for frequent connection with the server. When using a secure HTTPS connection, the difference would be more noticeable, since The SSL Handshake procedure is much harder than the TCP Handshake procedure.



An important parameter to keep alive is the keep alive duration. It means time interval. If several HTTP requests come within this interval, then the already established TCP connection will be reused.



The figure shows that the time between the fourth and third request exceeded the keep alive duration, so a new TCP connection is created with the server.
Let's see how you can adjust the above parameter. In the case of HttpClient, everything is fine, we have the ConnectionKeepAliveStrategy interface. By overriding the getKeepAliveDuration method, we can return the desired value of the keep alive duration parameter.

httpClient.setKeepAliveStrategy( new ConnectionKeepAliveStrategy() { @Override public long getKeepAliveDuration( HttpResponse response, HttpContext context) { return KEEP_ALIVE_DURATION_MILLISECONDS; } }); 


When working with HttpUrlConnection, you need to remember about the bug in the Android 2.2 platform and disable keep alive on platforms <= 2.2.

 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { System.setProperty("http.keepAlive", "false"); } 

The second unpleasant (perhaps only for me) moment when working with HttpUrlConnection is that the keep alive duration parameter is not configurable (I did not find a legal way, if someone tells me, I will be grateful). By default it is approximately 5 seconds.
Also, when working with keep alive connection, you should try to read data completely from the established connection (connection). If you don’t read the data in Donets, you can get connections that will hang in the pool and “think” that someone else is going to read them. If the InputStream is successfully received, read the entire response body. A complete subtraction clears the connection from the data, and this connection will be reused more likely.

Work with cookies

Cook is a small piece of data sent by a web server and stored on the user's computer. In our case, the computer is an Android device. In practice, cookies are usually used to authenticate a user, store their personal preferences and settings, track the status of a user's access session, and keep statistics about users. A large number of services begin to develop mobile applications after the mobile version of the site has already been made. In such a situation, an interesting question is: “Is it possible, having received an authorization cookie in a mobile application, to install it in a browser (in a WebView)?”. When solving this problem, there are a couple of details that will help save your time:

  1. On the surface> = 4.0.3 (API Level 15) there should be a dot at the beginning of the domain
  2. After calling the sync () method in CookieSyncManager, the cookie will be entered only in the WebView inside your application, but not in the browser . This restriction is imposed by the Android system for security reasons.




Secure connection (https)

To conclude this article, I will look at how to enable HTTPS in Android. As far as I know, on other mobile platforms, it is enough to enable the HTTPS scheme, the SSL transport mechanism - and everything should work. There are some problems in Android that should be considered and solved. First, remember how a secure connection is established. The red arrow points to the problem point - this is certificate authentication.



On platforms <Android 4.0, if you try to perform a network request over HTTPS, an SSLHandshakeException will crash. The ability to install a trusted certificate appeared on Android 4.0 using the KeyChain API. But what about platforms below 4.0? On these platforms we have two ways:

  1. Create a local certificate store
  2. Trust any certificates. In this case, the traffic will also be encrypted, but the threat of man in the middle will remain


If the choice fell on the creation of a local certificate store, then after it is created, you can connect it as follows:

- in the case of HttpUrlConnection:
...
 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm); KeyStore keyStore = KeyStore.getInstance("BKS"); InputStream in = context.getResources().openRawResource(mykeystore); keyStore.load(in, "mysecret".toCharArray()); in.close(); tmf.init(keyStore); SSLContext sslc = SSLContext.getInstance("TLS"); sslc.init(null, tmf.getTrustManagers(),new SecureRandom()); 

...
- in the case of HttpClient:
 private SSLSocketFactory createSslSocketFactory() { SSLSocketFactory sf = null; try { KeyStore keyStore = KeyStore.getInstance("BKS"); InputStream in = context.getResources().openRawResource(mykeystore); keyStore.load(in, "mysecret".toCharArray()); in.close(); sf = new SSLSocketFactory(keyStore); sf.setHostnameVerifier(STRICT_HOSTNAME_VERIFIER); } catch (Exception e) { e.printStackTrace(); } return sf; }. 


With the help of KeyStore.getInstance (“BKS”), we get a KeyStore object that supports the Bounce Castle KeyStore format (a Java package for working with crypto-algorithms). mykeystore - id of the resource in which the certificates are located.
mysecret - KeyStore password. More information can be found at the link to the local certificate store above.

If the choice fell on “Trust with any certificate”, then it suffices to implement two interfaces as follows:

 private class DummyHostnameVerifier implements HostnameVerifier{ @Override public boolean verify(String hostname, SSLSession session) { return true; } } private class DummyTrustManager implements X509TrustManager{ @Override public void checkClientTrusted(...) throws CertificateException { //empty } @Override public void checkServerTrusted(...) throws CertificateException { //empty } ... } 


You should then apply these implementations either to HttpClient or to HttpUrlConnection.

And what about the battery?

Battery consumption directly depends on the number of server connections being established, since Each installation activates a wireless radio that consumes battery power. How Android wireless radio works and what affects battery consumption, I recommend reading in this article: Transferring Data Without Draining the Battery .

After reading the article, you probably wondered which tool to use - HttpClient or HttpUrlConnection? Android developers recommend using HttpUrlConnection in new applications, since it is easy to use, it will be developed further and adapted to the platform. HttpClient should be used on platforms below Android 2.3, primarily because of a serious bug with a keep alive connection.

These three points we, of course, take into account when developing our mobile applications. And what, in the first place, do you think?

Source: https://habr.com/ru/post/185696/


All Articles