diff --git a/app/src/main/java/dnsfilter/android/BootUpReceiver.java b/app/src/main/java/dnsfilter/android/BootUpReceiver.java index 444a4ed17c3f13a9da71842bc0ca4e4204c2249c..4dd2c9ee4b2e2be135099211e4024956dad4a730 100644 --- a/app/src/main/java/dnsfilter/android/BootUpReceiver.java +++ b/app/src/main/java/dnsfilter/android/BootUpReceiver.java @@ -31,7 +31,6 @@ import android.net.VpnService; import android.os.Build; import foundation.e.trackerfilter.DNSBlockerService; -import foundation.e.trackerfilter.StatsIntentService; import util.ExecutionEnvironment; public class BootUpReceiver extends BroadcastReceiver { @@ -48,8 +47,6 @@ public class BootUpReceiver extends BroadcastReceiver { context.startForegroundService(i); i = new Intent(context, DNSBlockerService.class); context.startForegroundService(i); - i = new Intent(context, StatsIntentService.class); - context.startForegroundService(i); } else { DNSProxyActivity.BOOT_START = true; Intent i = new Intent(context, DNSProxyActivity.class); diff --git a/app/src/main/java/foundation/e/trackerfilter/DNSBlockerRunnable.java b/app/src/main/java/foundation/e/trackerfilter/DNSBlockerRunnable.java index 648fdc33a7e9bb5681980b9f2024545448b51830..c7484a52b0859d6c1223c2b8f3894899fd63b59c 100644 --- a/app/src/main/java/foundation/e/trackerfilter/DNSBlockerRunnable.java +++ b/app/src/main/java/foundation/e/trackerfilter/DNSBlockerRunnable.java @@ -51,11 +51,13 @@ public class DNSBlockerRunnable implements Runnable { ServerSocket resolverReceiver; boolean stopped = false; int port = 8888; + private TrackersLogger trackersLogger; private final String TAG = DNSBlockerRunnable.class.getName(); - public DNSBlockerRunnable(Context ct, int port) { + public DNSBlockerRunnable(Context ct, int port, TrackersLogger trackersLogger) { this.mContext = ct; this.port = port; + this.trackersLogger = trackersLogger; } public static void init(Context context){ @@ -72,16 +74,13 @@ public class DNSBlockerRunnable implements Runnable { public void run() { init(mContext); try { - resolverReceiver - = new ServerSocket(8888); - + resolverReceiver = new ServerSocket(8888); // ExecutionEnvironment.getEnvironment().protectSocket(resolverReceiver, 1); - } catch (IOException eio) { - Logger.getLogger().logLine("Exception:Cannot open DNS port " + port + "!" + eio.getMessage()); + Log.e(TAG, "Exception:Cannot open DNS port " + port + "!" + eio.getMessage()); return; } - Logger.getLogger().logLine("DNSFilterProxy running on port " + port + "!"); + Log.d(TAG, "DNSFilterProxy running on port " + port + "!"); while (!stopped) { try { @@ -124,7 +123,7 @@ public class DNSBlockerRunnable implements Runnable { } } - StatsIntentService.startActionLog(mContext, domainName, appUid, shouldBlock); + trackersLogger.logAccess(domainName, appUid, shouldBlock); } } if(!shouldBlock) { @@ -151,8 +150,7 @@ public class DNSBlockerRunnable implements Runnable { public synchronized void stop() { - //stopped = true; - + stopped = true; } diff --git a/app/src/main/java/foundation/e/trackerfilter/DNSBlockerService.java b/app/src/main/java/foundation/e/trackerfilter/DNSBlockerService.java index 320e67c2fa5ac8da6601a86e98da9cc68aac9b58..572c8e0af77adf35d26757c5d9ea4ac3215c29a8 100644 --- a/app/src/main/java/foundation/e/trackerfilter/DNSBlockerService.java +++ b/app/src/main/java/foundation/e/trackerfilter/DNSBlockerService.java @@ -23,15 +23,22 @@ package foundation.e.trackerfilter; import android.app.Service; import android.content.Intent; import android.os.IBinder; +import android.util.Log; import java.io.IOException; import dnsfilter.DNSFilterManager; public class DNSBlockerService extends Service { + private static final String TAG = "DNSBlockerService"; private static DNSBlockerRunnable sDNSBlocker; + private TrackersLogger trackersLogger; private static DNSFilterManager sDnsFilter; + public static final String ACTION_START = "foundation.e.privacymodules.trackers.intent.action.START"; + + public static final String EXTRA_ENABLE_NOTIFICATION = "foundation.e.privacymodules.trackers.intent.extra.ENABLED_NOTIFICATION"; + public DNSBlockerService() { } @@ -48,24 +55,53 @@ public class DNSBlockerService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { + if (intent.getBooleanExtra(EXTRA_ENABLE_NOTIFICATION, true)) { + ForegroundStarter.startForeground(this); + } + sDnsFilter = DNSFilterManager.getInstance(); + try { try { sDnsFilter.init(); } catch (IllegalStateException e){ //fired if already running - } - sDNSBlocker = new DNSBlockerRunnable(this,8888); - new Thread(sDNSBlocker).start(); } catch (IOException e) { sDnsFilter = null; e.printStackTrace(); } - ForegroundStarter.startForeground(this); + + + if (ACTION_START.equals(intent.getAction())) { + stop(); + start(); + } return START_STICKY; + } + private void start() { + try { + trackersLogger = new TrackersLogger(this); + sDNSBlocker = new DNSBlockerRunnable(this, 8888, trackersLogger); + + new Thread(sDNSBlocker).start(); + } catch(Exception e) { + Log.e(TAG, "Error while starting DNSBlocker service", e); + stop(); + } + + } + + private void stop() { + if (sDNSBlocker != null) { + sDNSBlocker.stop(); + } + sDNSBlocker = null; + if (trackersLogger != null) { + trackersLogger.stop(); + } + trackersLogger = null; } - -} \ No newline at end of file +} diff --git a/app/src/main/java/foundation/e/trackerfilter/EBootupReceiver.java b/app/src/main/java/foundation/e/trackerfilter/EBootupReceiver.java deleted file mode 100644 index f5aae6566b48864d479697902fdcb9b9610ef50f..0000000000000000000000000000000000000000 --- a/app/src/main/java/foundation/e/trackerfilter/EBootupReceiver.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright (C) 2021 ECORP - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - */ - -package foundation.e.trackerfilter; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.net.VpnService; -import android.os.Build; - -import java.util.Properties; - -import dnsfilter.android.AndroidEnvironment; -import dnsfilter.android.DNSFilterService; -import dnsfilter.android.DNSProxyActivity; - -public class EBootupReceiver extends BroadcastReceiver { - - @Override - public void onReceive(Context context, Intent intent) { - AndroidEnvironment.initEnvironment(context); - if (Build.VERSION.SDK_INT >= 28) { - Intent i = new Intent(context, DNSBlockerService.class); - context.startForegroundService(i); - i = new Intent(context, StatsIntentService.class); - context.startService(i); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/trackerfilter/StatsIntentService.java b/app/src/main/java/foundation/e/trackerfilter/StatsIntentService.java deleted file mode 100644 index a377451233838d6075990da1c105d5fdef0c60e4..0000000000000000000000000000000000000000 --- a/app/src/main/java/foundation/e/trackerfilter/StatsIntentService.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - Copyright (C) 2021 ECORP - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - */ - - -package foundation.e.trackerfilter; - -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.IBinder; -import android.util.Log; - -import foundation.e.privacymodules.trackers.Tracker; - - -public class StatsIntentService extends Service { - - private static final String ACTION_LOG = "dnsfilter.action.log"; - - // TODO: Rename parameters - private static final String EXTRA_DOMAIN_NAME = "domain_name"; - private static final String EXTRA_APP_UID = "app_uid"; - private static final String EXTRA_BLOCKED = "blocked"; - private static final String TAG = StatsIntentService.class.getName(); - - - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - /** - * Start the intent service to log tracker access to database - * @param context - * @param domainName - * @param appUid - */ - public static void startActionLog(Context context, String domainName, int appUid, boolean wasBlocked) { - Intent intent = new Intent(context, StatsIntentService.class); - intent.setAction(ACTION_LOG); - intent.putExtra(EXTRA_DOMAIN_NAME, domainName); - intent.putExtra(EXTRA_APP_UID, appUid); - intent.putExtra(EXTRA_BLOCKED, wasBlocked); - context.startService(intent); - } - - public int onStartCommand(Intent intent, int flags, int startId) { - int start = super.onStartCommand(intent, flags, startId); - if (intent != null) { - final String action = intent.getAction(); - if (ACTION_LOG.equals(action)) { - final String domaineName = intent.getStringExtra(EXTRA_DOMAIN_NAME); - final int appUid = intent.getIntExtra(EXTRA_APP_UID,-1); - handleActionLog(domaineName, appUid, intent.getBooleanExtra(EXTRA_BLOCKED, false)); - } - } - ForegroundStarter.startForeground(this); - return start; - } - - - private void handleActionLog(String domainName, int appId, boolean wasBlocked) { - Tracker tracker = TrackerListManager.getInstance(this).getTrackerByDomainName(domainName); - if(tracker == null){ - tracker = new Tracker(-1, domainName, domainName, -1, null, null); - tracker = TrackerListManager.getInstance(this).addTracker(tracker); - } - StatsDatabase database = StatsDatabase.getInstance(this); - database.logAccess(tracker.getId(),appId, wasBlocked); - } - - -} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/trackerfilter/TrackersLogger.java b/app/src/main/java/foundation/e/trackerfilter/TrackersLogger.java new file mode 100644 index 0000000000000000000000000000000000000000..9eadf5957e57f7388ea0e5d80d52d466b3899d5b --- /dev/null +++ b/app/src/main/java/foundation/e/trackerfilter/TrackersLogger.java @@ -0,0 +1,75 @@ +package foundation.e.trackerfilter; + +import android.content.Context; +import android.util.Log; + +import java.util.concurrent.LinkedBlockingQueue; + +import foundation.e.privacymodules.trackers.Tracker; + + +public class TrackersLogger { + private static final String TAG = "TrackersLogger"; + private StatsDatabase database; + private TrackerListManager trackerListManager; + + private LinkedBlockingQueue queue; + private boolean stopped = false; + + + public TrackersLogger(Context context) { + trackerListManager = TrackerListManager.getInstance(context); + database = StatsDatabase.getInstance(context); + queue = new LinkedBlockingQueue(); + startWriteLogLoop(); + } + + public void stop() { + stopped = true; + } + + public void logAccess(String domainName, int appId, boolean wasBlocked) { + queue.offer(new DetectedTracker(domainName, appId, wasBlocked)); + } + + private void startWriteLogLoop() { + Runnable writeLogRunner = new Runnable() { + @Override + public void run() { + while(!stopped) { + try { + logAccess(queue.take()); + } catch (InterruptedException e) { + Log.e(TAG, "writeLogLoop detectedTrackersQueue.take() interrupted: ", e); + } + } + } + }; + new Thread(writeLogRunner).start(); + } + + // TODO add a queue, perform the action in another thread ! + public void logAccess(DetectedTracker detectedTracker) { + + Tracker tracker = trackerListManager.getTrackerByDomainName(detectedTracker.domainName); + if(tracker == null){ + tracker = new Tracker(-1, detectedTracker.domainName, detectedTracker.domainName, -1, null, null); + tracker = trackerListManager.addTracker(tracker); + } + database.logAccess(tracker.getId(), detectedTracker.appUid, detectedTracker.wasBlocked); + } + + private class DetectedTracker { + String domainName; + int appUid; + boolean wasBlocked; + + public DetectedTracker(String domainName, int appId, boolean wasBlocked) { + this.domainName = domainName; + this.appUid = appUid; + this.wasBlocked = wasBlocked; + } + } + +} + diff --git a/app/src/main/java/foundation/e/trackerfilter/api/TrackTrackersPrivacyModule.java b/app/src/main/java/foundation/e/trackerfilter/api/TrackTrackersPrivacyModule.java index 9224ae17c234c7d357f8c0a8002ee5bc55f0dc3b..d1495819453065ed01dfabe567acb830bebaa116 100644 --- a/app/src/main/java/foundation/e/trackerfilter/api/TrackTrackersPrivacyModule.java +++ b/app/src/main/java/foundation/e/trackerfilter/api/TrackTrackersPrivacyModule.java @@ -21,6 +21,7 @@ package foundation.e.trackerfilter.api; import android.content.Context; +import android.content.Intent; import org.jetbrains.annotations.NotNull; @@ -28,6 +29,7 @@ import java.util.List; import foundation.e.privacymodules.trackers.ITrackTrackersPrivacyModule; import foundation.e.privacymodules.trackers.Tracker; +import foundation.e.trackerfilter.DNSBlockerService; import foundation.e.trackerfilter.StatsDatabase; public class TrackTrackersPrivacyModule implements ITrackTrackersPrivacyModule { @@ -38,6 +40,14 @@ public class TrackTrackersPrivacyModule implements ITrackTrackersPrivacyModule { mContext = ct; } + + public void start(List trackers, boolean enableNotification) { + // TODO: pass to the service as global var. + Intent intent = new Intent(mContext, DNSBlockerService.class); + intent.putExtra(DNSBlockerService.EXTRA_ENABLE_NOTIFICATION, enableNotification); + mContext.startService(intent); + } + @Override public List getPastDayTrackersCalls() { return StatsDatabase.getInstance(mContext).getPast24h(); diff --git a/build.gradle b/build.gradle index 92a34ba5aa69b4941056a71367d614a4d473e42d..632c1ff58e88f097526a7a910b7fe3915408e796 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:4.1.1' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20" } } diff --git a/demoapp/.gitignore b/demoapp/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..42afabfd2abebf31384ca7797186a27a4b7dbee8 --- /dev/null +++ b/demoapp/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/demoapp/build.gradle b/demoapp/build.gradle new file mode 100644 index 0000000000000000000000000000000000000000..4e94d120800e1b2aa4fc305ddb3a59458560139d --- /dev/null +++ b/demoapp/build.gradle @@ -0,0 +1,43 @@ +plugins { + id 'com.android.application' + id 'kotlin-android' +} + +android { + compileSdkVersion 30 + + defaultConfig { + applicationId "foudation.e.privacymodules.trackers.demoapp" + minSdkVersion 29 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + implementation project(':app') + implementation 'foundation.e:privacymodule.api:0.4.3' + + implementation 'androidx.core:core-ktx:1.6.0' + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.0' + +} \ No newline at end of file diff --git a/demoapp/proguard-rules.pro b/demoapp/proguard-rules.pro new file mode 100644 index 0000000000000000000000000000000000000000..481bb434814107eb79d7a30b676d344b0df2f8ce --- /dev/null +++ b/demoapp/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/demoapp/src/androidTest/java/foudation/e/privacymodules/trackers/demoapp/ExampleInstrumentedTest.kt b/demoapp/src/androidTest/java/foudation/e/privacymodules/trackers/demoapp/ExampleInstrumentedTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..5bf7c14ff95cefd0c194d13b24fd7b3cc86f9604 --- /dev/null +++ b/demoapp/src/androidTest/java/foudation/e/privacymodules/trackers/demoapp/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package foudation.e.privacymodules.trackers.demoapp + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("foudation.e.privacymodules.trackers.demoapp", appContext.packageName) + } +} \ No newline at end of file diff --git a/demoapp/src/main/AndroidManifest.xml b/demoapp/src/main/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..9626f57fbaa357996be512d4e565269abd83cf54 --- /dev/null +++ b/demoapp/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demoapp/src/main/java/foudation/e/privacymodules/trackers/demoapp/MainActivity.kt b/demoapp/src/main/java/foudation/e/privacymodules/trackers/demoapp/MainActivity.kt new file mode 100644 index 0000000000000000000000000000000000000000..930ad61ea009002a904e82c482634a3adfa84ac1 --- /dev/null +++ b/demoapp/src/main/java/foudation/e/privacymodules/trackers/demoapp/MainActivity.kt @@ -0,0 +1,26 @@ +package foudation.e.privacymodules.trackers.demoapp + +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.view.View +import android.widget.Button +import foundation.e.privacymodules.trackers.ITrackTrackersPrivacyModule +import foundation.e.privacymodules.trackers.Tracker +import foundation.e.trackerfilter.api.TrackTrackersPrivacyModule + +class MainActivity : AppCompatActivity() { + + private var mBtnStart: Button? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + mBtnStart = findViewById(R.id.button_start) + + + mBtnStart?.setOnClickListener { v: View? -> + TrackTrackersPrivacyModule(applicationContext).start(emptyList(), true); + } + } +} \ No newline at end of file diff --git a/demoapp/src/main/res/drawable-v24/ic_launcher_foreground.xml b/demoapp/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000000000000000000000000000000000000..2b068d11462a4b96669193de13a711a3a36220a0 --- /dev/null +++ b/demoapp/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/demoapp/src/main/res/drawable/ic_launcher_background.xml b/demoapp/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..07d5da9cbf141911847041df5d7b87f0dd5ef9d4 --- /dev/null +++ b/demoapp/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demoapp/src/main/res/layout/activity_main.xml b/demoapp/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000000000000000000000000000000000000..f65787d471a2d7c8809faeedb64802d23962f6a8 --- /dev/null +++ b/demoapp/src/main/res/layout/activity_main.xml @@ -0,0 +1,23 @@ + + + +