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

Adds functionality to automatically test new networks #513

Closed
wants to merge 8 commits into from
5 changes: 4 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,10 @@
android:name=".common.service.RunTestJobService"
android:label="Run Test Service"
android:permission="android.permission.BIND_JOB_SERVICE"/>

<service
android:name=".common.service.ConnectivityChangeService"
android:enabled="true"
android:exported="true"/>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
import org.openobservatory.engine.OONICheckInConfig;
import org.openobservatory.ooniprobe.BuildConfig;
import org.openobservatory.ooniprobe.client.OONIAPIClient;
import org.openobservatory.ooniprobe.common.service.ConnectivityChangeService;
import org.openobservatory.ooniprobe.common.service.RunTestService;
import org.openobservatory.ooniprobe.common.service.ServiceUtil;
import org.openobservatory.ooniprobe.common.service.ServiceUtil;
import org.openobservatory.ooniprobe.di.ActivityComponent;
import org.openobservatory.ooniprobe.di.AppComponent;
import org.openobservatory.ooniprobe.di.ApplicationModule;
Expand Down Expand Up @@ -64,6 +67,9 @@ public class Application extends android.app.Application {
Measurement.deleteOldLogs(Application.this);
});
ThirdPartyServices.reloadConsents(Application.this);
if (_preferenceManager.isAutomaticallyRunTestOnNetworkChange()){
ServiceUtil.scheduleConnectivityChangeService(this);
}
LocaleUtils.setLocale(new Locale(_preferenceManager.getSettingsLanguage()));
LocaleUtils.updateConfig(this, getBaseContext().getResources().getConfiguration());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.openobservatory.ooniprobe.common;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.os.Build;
import android.util.Log;

import androidx.annotation.NonNull;

import javax.inject.Inject;

public class ConnectivityChangeUtil extends ConnectivityManager.NetworkCallback {
@Inject
NetworkChangeProcessor networkChangeProcessor;

private static final String TAG = ConnectivityChangeUtil.class.getSimpleName();
private final NetworkRequest mNetworkRequest;
private final ConnectivityManager mConnectivityManager;

// Constructor
public ConnectivityChangeUtil(Context context) {
mNetworkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
.build();

mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);

Application app = ((Application) context.getApplicationContext());
app.component.serviceComponent().inject(this);
}

@Override
public void onAvailable(@NonNull Network network) {
super.onAvailable(network);
if (isNetworkAvailable(network)) {
networkChangeProcessor.processNetworkPossibleNetworkChange();
}
Log.d(TAG, "onAvailable() called: Connected to network");
}

private Boolean isNetworkAvailable(Network network) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (network == null) return false;
NetworkCapabilities actNw = mConnectivityManager.getNetworkCapabilities(network);
return actNw != null && (actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|| actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|| actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET));
} else {
NetworkInfo nwInfo = mConnectivityManager.getActiveNetworkInfo();
return nwInfo != null && nwInfo.isConnected();
}
}

@Override
public void onLost(@NonNull Network network) {
super.onLost(network);
Log.e(TAG, "onLost() called: Lost network connection");
}

/**
* Check current Network state
*/
public void checkNetworkState() {
try {
NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
networkChangeProcessor.processNetworkPossibleNetworkChange();
}
} catch (Exception exception) {
exception.printStackTrace();
}
}

/**
* Registers the Network-Request callback
* (Note: Register only once to prevent duplicate callbacks)
*/
public void registerNetworkCallbackEvents() {
Log.d(TAG, "registerNetworkCallbackEvents() called");
mConnectivityManager.registerNetworkCallback(mNetworkRequest, this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.openobservatory.ooniprobe.common;

import org.openobservatory.engine.LoggerArray;
import org.openobservatory.engine.OONIGeolocateResults;
import org.openobservatory.engine.OONISession;
import org.openobservatory.ooniprobe.BuildConfig;
import org.openobservatory.ooniprobe.common.service.ServiceUtil;
import org.openobservatory.ooniprobe.test.EngineProvider;

import java.util.Objects;

import javax.inject.Inject;


public class NetworkChangeProcessor {

private final PreferenceManager pm;
private final Application app;

@Inject
NetworkChangeProcessor(Application application, PreferenceManager pm) {
this.pm = pm;
this.app = application;
}


public void processNetworkPossibleNetworkChange() {
try {
OONISession session = EngineProvider.get().newSession(
EngineProvider.get().getDefaultSessionConfig(
app,
BuildConfig.SOFTWARE_NAME,
BuildConfig.VERSION_NAME,
new LoggerArray(),
pm.getProxyURL()
)
);
OONIGeolocateResults geoLocateResults = session.geolocate(session.newContext());
System.out.println(pm.getLastKnownNetwork());
if (!Objects.equals(pm.getLastKnownNetwork(), geoLocateResults.getASN())) {
pm.setLastKnownNetwork(geoLocateResults.getASN());
ServiceUtil.startRunTestServiceNetworkChanged(app);
}
} catch (Exception e) {
ThirdPartyServices.logException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ public String getProxyHostname() {
return sp.getString(r.getString(R.string.proxy_hostname), "");
}

public void setLastKnownNetwork(String network) {
sp.edit().putString("last_known_network", network).apply();
}

public String getLastKnownNetwork() {
return sp.getString("last_known_network", "");
}

public void setProxyHostname(String value) {
sp.edit()
.putString(r.getString(R.string.proxy_hostname), value)
Expand Down Expand Up @@ -316,6 +324,10 @@ public boolean isAskAutomaticTestDialogDisabled() {
return sp.getBoolean(AUTOTEST_DIALOG_DISABLE, false);
}

public boolean isAutomaticallyRunTestOnNetworkChange(){
return sp.getBoolean(r.getString(R.string.automatically_run_test_on_network_change), true);
}

public void disableAskAutomaticTestDialog() {
sp.edit().putBoolean(AUTOTEST_DIALOG_DISABLE, true)
.apply();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.openobservatory.ooniprobe.common.service;

import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;

import org.openobservatory.ooniprobe.common.ConnectivityChangeUtil;
import org.openobservatory.ooniprobe.receiver.ConnectivityReceiver;

public class ConnectivityChangeService extends Service {

private static final String TAG = ConnectivityChangeService.class.getSimpleName();
private ConnectivityReceiver receiver = null;

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}

@Override
public void onCreate() {
super.onCreate();
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

ConnectivityChangeUtil mNetworkMonitoringUtil = new ConnectivityChangeUtil(getApplicationContext());
// Check the network state before registering for the 'networkCallbackEvents'
// mNetworkMonitoringUtil.checkNetworkState();
mNetworkMonitoringUtil.registerNetworkCallbackEvents();
} else {
// Create a network change broadcast receiver.
receiver = new ConnectivityReceiver();
// Register the broadcast receiver with the intent filter object.
registerReceiver(receiver, ConnectivityReceiver.intentFilter());
}

Log.d(TAG, "Service onCreate: ConnectivityReceiver is registered.");
}

@Override
public void onDestroy() {
super.onDestroy();
// Unregister screenOnOffReceiver when destroy.
if (receiver != null) {
unregisterReceiver(receiver);
Log.d(TAG, "Service onDestroy: ConnectivityReceiver is unregistered.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.openobservatory.ooniprobe.test.suite.ExperimentalSuite;
import org.openobservatory.ooniprobe.test.suite.InstantMessagingSuite;
import org.openobservatory.ooniprobe.test.suite.PerformanceSuite;
import org.openobservatory.ooniprobe.test.suite.WebsitesSuite;

import java.util.ArrayList;

Expand Down Expand Up @@ -89,6 +90,33 @@ public static void startRunTestServiceUnattended(Application app) {
ServiceUtil.startRunTestServiceCommon(app, testSuites, false, true);
d.generateAutoRunServiceSuite.markAsRan();

}

/**
* Start Tests on Network Changed event.
* @param app
* Application context used to start `RunTestService`.
*/
public static void startRunTestServiceNetworkChanged(Application app) {
app.getServiceComponent().inject(d);

boolean isVPNInUse = ReachabilityManager.isVPNinUse(app);

OONICheckInConfig config = app.getOONICheckInConfig();

if (!d.generateAutoRunServiceSuite.shouldStart(config.isOnWiFi(),config.isCharging(), isVPNInUse)) {
return;
}

// Tag tests with identifier required to set Settings$Options#software_name
ArrayList<AbstractSuite> testSuites = new ArrayList<>();
testSuites.add(new WebsitesSuite());
testSuites.add(new InstantMessagingSuite());
testSuites.add(new CircumventionSuite());
testSuites.add(new PerformanceSuite());
testSuites.add(new ExperimentalSuite());
startRunTestServiceCommon(app, testSuites, false, true);

}


Expand All @@ -108,6 +136,16 @@ private static void startRunTestServiceCommon(Context context, ArrayList<Abstrac
ContextCompat.startForegroundService(context, serviceIntent);
}

public static void scheduleConnectivityChangeService(Context context) {
Intent backgroundService = new Intent(context.getApplicationContext(), ConnectivityChangeService.class);
context.startService(backgroundService);
}

public static void stopConnectivityChangeService(Context context) {
Intent myService = new Intent(context, ConnectivityChangeService.class);
context.stopService(myService);
}

public static class Dependencies {
@Inject
GenerateAutoRunServiceSuite generateAutoRunServiceSuite;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import org.openobservatory.ooniprobe.common.service.RunTestJobService;
import org.openobservatory.ooniprobe.common.service.ServiceUtil;
import org.openobservatory.ooniprobe.di.annotations.PerService;
import org.openobservatory.ooniprobe.common.ConnectivityChangeUtil;
import org.openobservatory.ooniprobe.receiver.ConnectivityReceiver;

import dagger.Subcomponent;

Expand All @@ -12,5 +14,7 @@
public interface ServiceComponent {
void inject(ResubmitTask.Dependencies dependencies);
void inject(RunTestJobService service);
void inject(ConnectivityReceiver connectivityReceiver);
void inject(ConnectivityChangeUtil connectivityReceiver);
void inject(ServiceUtil.Dependencies dependencies);
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin
ServiceUtil.stopJob(getContext());
}
}
if (key.equals(getString(R.string.automatically_run_test_on_network_change))) {
if (sharedPreferences.getBoolean(key, false)) {
ServiceUtil.scheduleConnectivityChangeService(getContext());
} else {
ServiceUtil.stopConnectivityChangeService(getContext());
}
}
if (key.equals(getString(R.string.automated_testing_charging)) ||
key.equals(getString(R.string.automated_testing_wifionly))){
//stop and re-enable scheduler in case of wifi charging option changed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.openobservatory.ooniprobe.receiver;


import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

import org.openobservatory.ooniprobe.common.Application;
import org.openobservatory.ooniprobe.common.NetworkChangeProcessor;

import javax.inject.Inject;

public class ConnectivityReceiver extends BroadcastReceiver {
@Inject
NetworkChangeProcessor networkChangeProcessor;

@Override
public void onReceive(Context context, Intent intent) {
Application app = ((Application) context.getApplicationContext());
app.component.serviceComponent().inject(this);
final String action = intent.getAction();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
ConnectivityManager connMgr = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
networkChangeProcessor.processNetworkPossibleNetworkChange();
}
}
}

public static IntentFilter intentFilter(){
// Create an IntentFilter instance.
IntentFilter intentFilter = new IntentFilter();
// Add network connectivity change action.
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
// Set broadcast receiver priority.
intentFilter.setPriority(100);
return intentFilter;
}
}
Loading
Loading