Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include mobile country code in Analytics events #226

Merged
merged 5 commits into from Nov 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -17,7 +17,7 @@

import android.os.SystemClock;
import android.util.Log;
import app.intra.sys.LogWrapper;
import app.intra.sys.firebase.LogWrapper;
import java.net.InetAddress;
import java.net.ProtocolException;

Expand Down
2 changes: 1 addition & 1 deletion Android/app/src/main/java/app/intra/net/doh/Resolver.java
Expand Up @@ -17,7 +17,7 @@

import android.util.Log;
import app.intra.net.dns.DnsUdpQuery;
import app.intra.sys.LogWrapper;
import app.intra.sys.firebase.LogWrapper;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.nio.BufferOverflowException;
Expand Down
56 changes: 19 additions & 37 deletions Android/app/src/main/java/app/intra/net/go/GoIntraListener.java
Expand Up @@ -15,15 +15,13 @@
*/
package app.intra.net.go;

import android.os.Bundle;
import android.os.SystemClock;
import androidx.collection.LongSparseArray;
import app.intra.net.dns.DnsPacket;
import app.intra.net.doh.Transaction;
import app.intra.net.doh.Transaction.Status;
import app.intra.sys.firebase.AnalyticsWrapper;
import app.intra.sys.IntraVpnService;
import app.intra.sys.Names;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.perf.FirebasePerformance;
import com.google.firebase.perf.metrics.HttpMetric;
import doh.Doh;
Expand All @@ -47,28 +45,20 @@ public class GoIntraListener implements tunnel.IntraListener {
private static final int UDP_THRESHOLD_BYTES = 10000;

private final IntraVpnService vpnService;
private final AnalyticsWrapper analytics;
GoIntraListener(IntraVpnService vpnService) {
this.vpnService = vpnService;
analytics = AnalyticsWrapper.get(vpnService);
}

@Override
public void onTCPSocketClosed(TCPSocketSummary summary) {
// We had a functional socket long enough to record statistics.
// Report the BYTES event :
// - UPLOAD: total bytes uploaded over the lifetime of a socket
// - DOWNLOAD: total bytes downloaded
// - PORT: TCP port number (i.e. protocol type)
// - TCP_HANDSHAKE_MS: TCP handshake latency in milliseconds
// - DURATION: socket lifetime in seconds
// - TODO: FIRST_BYTE_MS: Time between socket open and first byte from server, in milliseconds.

Bundle bytesEvent = new Bundle();
bytesEvent.putLong(Names.UPLOAD.name(), summary.getUploadBytes());
bytesEvent.putLong(Names.DOWNLOAD.name(), summary.getDownloadBytes());
bytesEvent.putInt(Names.PORT.name(), summary.getServerPort());
bytesEvent.putInt(Names.TCP_HANDSHAKE_MS.name(), summary.getSynack());
bytesEvent.putInt(Names.DURATION.name(), summary.getDuration());
FirebaseAnalytics.getInstance(vpnService).logEvent(Names.BYTES.name(), bytesEvent);
analytics.logTCP(
summary.getUploadBytes(),
summary.getDownloadBytes(),
summary.getServerPort(),
summary.getSynack(),
summary.getDuration());

RetryStats retry = summary.getRetry();
if (retry != null) {
Expand All @@ -77,20 +67,13 @@ public void onTCPSocketClosed(TCPSocketSummary summary) {
// Split-retry was not attempted.
return;
}
// Prepare an EARLY_RESET event to collect metrics on success rates for splitting:
// - BYTES : Amount uploaded before reset
// - CHUNKS : Number of upload writes before reset
// - TIMEOUT : Whether the initial connection failed with a timeout.
// - SPLIT : Number of bytes included in the first retry segment
// - RETRY : 1 if retry succeeded, otherwise 0
Bundle resetEvent = new Bundle();
resetEvent.putInt(Names.BYTES.name(), retry.getBytes());
resetEvent.putInt(Names.CHUNKS.name(), retry.getChunks());
resetEvent.putInt(Names.TIMEOUT.name(), retry.getTimeout() ? 1 : 0);
resetEvent.putInt(Names.SPLIT.name(), retry.getSplit());
boolean success = summary.getDownloadBytes() > 0;
resetEvent.putInt(Names.RETRY.name(), success ? 1 : 0);
FirebaseAnalytics.getInstance(vpnService).logEvent(Names.EARLY_RESET.name(), resetEvent);
analytics.logEarlyReset(
retry.getBytes(),
retry.getChunks(),
retry.getTimeout(),
retry.getSplit(),
success);
}
}

Expand All @@ -100,11 +83,10 @@ public void onUDPSocketClosed(UDPSocketSummary summary) {
if (totalBytes < UDP_THRESHOLD_BYTES) {
return;
}
Bundle event = new Bundle();
event.putLong(Names.UPLOAD.name(), summary.getUploadBytes());
event.putLong(Names.DOWNLOAD.name(), summary.getDownloadBytes());
event.putLong(Names.DURATION.name(), summary.getDuration());
FirebaseAnalytics.getInstance(vpnService).logEvent(Names.UDP.name(), event);
analytics.logUDP(
summary.getUploadBytes(),
summary.getDownloadBytes(),
summary.getDuration());
}

private static final LongSparseArray<Status> goStatusMap = new LongSparseArray<>();
Expand Down
4 changes: 2 additions & 2 deletions Android/app/src/main/java/app/intra/net/go/GoVpnAdapter.java
Expand Up @@ -24,9 +24,9 @@
import app.intra.net.doh.ServerConnectionFactory;
import app.intra.net.go.TLSProbe.Result;
import app.intra.sys.IntraVpnService;
import app.intra.sys.LogWrapper;
import app.intra.sys.firebase.LogWrapper;
import app.intra.sys.PersistentState;
import app.intra.sys.RemoteConfig;
import app.intra.sys.firebase.RemoteConfig;
import doh.Transport;
import java.io.IOException;
import java.util.Locale;
Expand Down
Expand Up @@ -21,7 +21,7 @@
import app.intra.net.doh.ResponseWriter;
import app.intra.net.doh.Transaction;
import app.intra.sys.IntraVpnService;
import app.intra.sys.LogWrapper;
import app.intra.sys.firebase.LogWrapper;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
Expand Down
11 changes: 3 additions & 8 deletions Android/app/src/main/java/app/intra/net/go/TLSProbe.java
Expand Up @@ -16,10 +16,8 @@
package app.intra.net.go;

import android.content.Context;
import android.os.Bundle;
import app.intra.sys.Names;
import app.intra.sys.RemoteConfig;
import com.google.firebase.analytics.FirebaseAnalytics;
import app.intra.sys.firebase.AnalyticsWrapper;
import app.intra.sys.firebase.RemoteConfig;
import java.io.IOException;
import java.net.URL;
import javax.net.ssl.SSLHandshakeException;
Expand Down Expand Up @@ -48,10 +46,7 @@ static Result run(Context context, String[] targets) {
for (String target : targets) {
Result r = probe(target);
if (context != null) {
Bundle b = new Bundle();
b.putString(Names.RESULT.name(), r.name());
b.putString(Names.SERVER.name(), target);
FirebaseAnalytics.getInstance(context).logEvent(Names.TLS_PROBE.name(), b);
AnalyticsWrapper.get(context).logTLSProbe(target, r.name());
}
if (r == Result.TLS_FAILED ||
(r == Result.OTHER_FAILED && worstResult == Result.SUCCESS)) {
Expand Down
Expand Up @@ -26,7 +26,7 @@
import app.intra.net.doh.ResponseWriter;
import app.intra.net.doh.Transaction;
import app.intra.sys.IntraVpnService;
import app.intra.sys.LogWrapper;
import app.intra.sys.firebase.LogWrapper;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
Expand Down
2 changes: 2 additions & 0 deletions Android/app/src/main/java/app/intra/sys/AutoStarter.java
Expand Up @@ -20,6 +20,8 @@
import android.content.Intent;
import android.net.VpnService;
import android.util.Log;
import app.intra.sys.firebase.LogWrapper;
import app.intra.sys.firebase.RemoteConfig;
import app.intra.ui.MainActivity;

/**
Expand Down
Expand Up @@ -15,36 +15,11 @@
*/
package app.intra.sys;

// Names for intents and events that are used by multiple components and must agree.
// Names for intents and settings that are used by multiple components or must remain consistent.
// Each name is used to generate a string.
public enum Names {
BOOTSTRAP,
BOOTSTRAP_FAILED,
BYTES,
CHUNKS,
public enum InternalNames {
CUSTOM_SERVER,
DNS_STATUS,
DOWNLOAD,
DURATION,
EARLY_RESET,
FIRST_BYTE_MS,
LATENCY,
MODE,
PORT,
RESULT,
RETRY,
SERVER,
SPLIT,
STARTVPN,
TCP_HANDSHAKE_MS,
TIMEOUT,
TLS_PROBE,
TRANSACTION,
TRY_ALL_ACCEPTED,
TRY_ALL_CANCELLED,
TRY_ALL_DIALOG,
TRY_ALL_FAILED,
TRY_ALL_REQUESTED,
UDP,
UPLOAD,
}
26 changes: 10 additions & 16 deletions Android/app/src/main/java/app/intra/sys/IntraVpnService.java
Expand Up @@ -30,7 +30,6 @@
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.util.Log;
Expand All @@ -43,9 +42,10 @@
import app.intra.net.doh.Transaction;
import app.intra.net.go.GoVpnAdapter;
import app.intra.net.split.SplitVpnAdapter;
import app.intra.sys.firebase.AnalyticsWrapper;
import app.intra.sys.NetworkManager.NetworkListener;
import app.intra.sys.firebase.LogWrapper;
import app.intra.ui.MainActivity;
import com.google.firebase.analytics.FirebaseAnalytics;
import java.util.Calendar;

public class IntraVpnService extends VpnService implements NetworkListener,
Expand Down Expand Up @@ -84,7 +84,7 @@ public class IntraVpnService extends VpnService implements NetworkListener,
// previously selected server.
private String pendingUrl = NO_PENDING_CONNECTION;

private FirebaseAnalytics firebaseAnalytics;
private AnalyticsWrapper analytics;

public boolean isOn() {
return vpnAdapter != null;
Expand Down Expand Up @@ -225,9 +225,7 @@ private void updateServerConnection() {

// Bootstrap the new server connection, which may require resolving the new server's name, using
// the current DNS configuration.
Bundle bootstrap = new Bundle();
bootstrap.putString(Names.SERVER.name(),
PersistentState.extractHostForAnalytics(this, url));
String analyticsHost = PersistentState.extractHostForAnalytics(this, url);
long beforeBootstrap = SystemClock.elapsedRealtime();
final ServerConnection newConnection = (new ServerConnectionFactory(this)).get(url);

Expand All @@ -236,11 +234,10 @@ private void updateServerConnection() {

// Measure bootstrap delay.
long afterBootStrap = SystemClock.elapsedRealtime();
bootstrap.putInt(Names.LATENCY.name(), (int) (afterBootStrap - beforeBootstrap));
firebaseAnalytics.logEvent(Names.BOOTSTRAP.name(), bootstrap);
analytics.logBootstrap(analyticsHost, (int) (afterBootStrap - beforeBootstrap));
} else {
controller.onConnectionStateChanged(this, ServerConnection.State.FAILING);
firebaseAnalytics.logEvent(Names.BOOTSTRAP_FAILED.name(), bootstrap);
analytics.logBootstrapFailed(analyticsHost);
}

// Step 3: Unset the flag and confirm the update.
Expand Down Expand Up @@ -302,7 +299,7 @@ public void onCreate() {
LogWrapper.log(Log.INFO, LOG_TAG, "Creating DNS VPN service");
VpnController.getInstance().setIntraVpnService(this);

firebaseAnalytics = FirebaseAnalytics.getInstance(this);
analytics = AnalyticsWrapper.get(this);

syncNumRequests();
}
Expand Down Expand Up @@ -383,10 +380,7 @@ private synchronized void startVpnAdapter() {
vpnAdapter = makeVpnAdapter();
if (vpnAdapter != null) {
vpnAdapter.start();

Bundle event = new Bundle();
event.putString(Names.MODE.name(), vpnAdapter.getClass().getSimpleName());
FirebaseAnalytics.getInstance(this).logEvent(Names.STARTVPN.name(), event);
analytics.logStartVPN(vpnAdapter.getClass().getSimpleName());
} else {
LogWrapper.log(Log.ERROR, LOG_TAG, "Failed to start VPN adapter!");
}
Expand Down Expand Up @@ -460,8 +454,8 @@ public void recordTransaction(Transaction transaction) {

getTracker().recordTransaction(this, transaction);

Intent intent = new Intent(Names.RESULT.name());
intent.putExtra(Names.TRANSACTION.name(), transaction);
Intent intent = new Intent(InternalNames.RESULT.name());
intent.putExtra(InternalNames.TRANSACTION.name(), transaction);
LocalBroadcastManager.getInstance(IntraVpnService.this).sendBroadcast(intent);

if (!networkConnected) {
Expand Down
8 changes: 4 additions & 4 deletions Android/app/src/main/java/app/intra/sys/NetworkManager.java
Expand Up @@ -25,24 +25,24 @@

// This class listens for network connectivity changes and notifies a NetworkListener of
// connected/disconnected events.
class NetworkManager {
public class NetworkManager {

private static final String LOG_TAG = "NetworkManager";
private static final String EXTRA_NETWORK_INFO = "networkInfo";

public interface NetworkListener {

public void onNetworkConnected(NetworkInfo networkInfo);
void onNetworkConnected(NetworkInfo networkInfo);

public void onNetworkDisconnected();
void onNetworkDisconnected();
}

private ConnectivityManager connectivityManager;
private BroadcastReceiver broadcastReceiver;
private Context applicationContext;
private NetworkListener networkListener;

NetworkManager(Context context, NetworkListener networkListener) {
public NetworkManager(Context context, NetworkListener networkListener) {
applicationContext = context.getApplicationContext();
connectivityManager =
(ConnectivityManager) applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE);
Expand Down
3 changes: 2 additions & 1 deletion Android/app/src/main/java/app/intra/sys/PersistentState.java
Expand Up @@ -23,6 +23,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.intra.R;
import app.intra.sys.firebase.LogWrapper;
import app.intra.ui.settings.Untemplate;
import java.net.MalformedURLException;
import java.net.URL;
Expand Down Expand Up @@ -160,7 +161,7 @@ public static String extractHostForAnalytics(Context context, String url) {
if (Arrays.asList(urls).contains(expanded)) {
return extractHost(expanded);
}
return Names.CUSTOM_SERVER.name();
return InternalNames.CUSTOM_SERVER.name();
}

private static SharedPreferences getApprovalSettings(Context context) {
Expand Down
2 changes: 1 addition & 1 deletion Android/app/src/main/java/app/intra/sys/VpnController.java
Expand Up @@ -57,7 +57,7 @@ synchronized void onConnectionStateChanged(Context context, ServerConnection.Sta
}

private void stateChanged(Context context) {
Intent broadcast = new Intent(Names.DNS_STATUS.name());
Intent broadcast = new Intent(InternalNames.DNS_STATUS.name());
LocalBroadcastManager.getInstance(context).sendBroadcast(broadcast);
}

Expand Down