| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
| 3  * Copyright (C) 2006-2016 Eyeo GmbH | 3  * Copyright (C) 2006-2016 Eyeo GmbH | 
| 4  * | 4  * | 
| 5  * Adblock Plus is free software: you can redistribute it and/or modify | 5  * Adblock Plus is free software: you can redistribute it and/or modify | 
| 6  * it under the terms of the GNU General Public License version 3 as | 6  * it under the terms of the GNU General Public License version 3 as | 
| 7  * published by the Free Software Foundation. | 7  * published by the Free Software Foundation. | 
| 8  * | 8  * | 
| 9  * Adblock Plus is distributed in the hope that it will be useful, | 9  * Adblock Plus is distributed in the hope that it will be useful, | 
| 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 12  * GNU General Public License for more details. | 12  * GNU General Public License for more details. | 
| 13  * | 13  * | 
| 14  * You should have received a copy of the GNU General Public License | 14  * You should have received a copy of the GNU General Public License | 
| 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
| 16  */ | 16  */ | 
| 17 | 17 | 
| 18 package org.adblockplus.libadblockplus.android; | 18 package org.adblockplus.libadblockplus.android; | 
| 19 | 19 | 
| 20 import java.util.ArrayList; | 20 import java.util.ArrayList; | 
| 21 import java.util.Arrays; | 21 import java.util.Arrays; | 
| 22 import java.util.Collection; | 22 import java.util.Collection; | 
| 23 import java.util.HashSet; | 23 import java.util.HashSet; | 
| 24 import java.util.List; | 24 import java.util.List; | 
| 25 import java.util.Locale; | 25 import java.util.Locale; | 
|  | 26 import java.util.Map; | 
| 26 import java.util.Set; | 27 import java.util.Set; | 
| 27 | 28 | 
| 28 import org.adblockplus.libadblockplus.AppInfo; | 29 import org.adblockplus.libadblockplus.AppInfo; | 
| 29 import org.adblockplus.libadblockplus.Filter; | 30 import org.adblockplus.libadblockplus.Filter; | 
| 30 import org.adblockplus.libadblockplus.FilterChangeCallback; | 31 import org.adblockplus.libadblockplus.FilterChangeCallback; | 
| 31 import org.adblockplus.libadblockplus.FilterEngine; | 32 import org.adblockplus.libadblockplus.FilterEngine; | 
| 32 import org.adblockplus.libadblockplus.FilterEngine.ContentType; | 33 import org.adblockplus.libadblockplus.FilterEngine.ContentType; | 
| 33 import org.adblockplus.libadblockplus.JsEngine; | 34 import org.adblockplus.libadblockplus.JsEngine; | 
| 34 import org.adblockplus.libadblockplus.LogSystem; | 35 import org.adblockplus.libadblockplus.LogSystem; | 
| 35 import org.adblockplus.libadblockplus.ShowNotificationCallback; | 36 import org.adblockplus.libadblockplus.ShowNotificationCallback; | 
| 36 import org.adblockplus.libadblockplus.Subscription; | 37 import org.adblockplus.libadblockplus.Subscription; | 
| 37 import org.adblockplus.libadblockplus.UpdateAvailableCallback; | 38 import org.adblockplus.libadblockplus.UpdateAvailableCallback; | 
| 38 import org.adblockplus.libadblockplus.UpdateCheckDoneCallback; | 39 import org.adblockplus.libadblockplus.UpdateCheckDoneCallback; | 
|  | 40 import org.adblockplus.libadblockplus.WebRequest; | 
| 39 | 41 | 
| 40 import android.content.Context; | 42 import android.content.Context; | 
| 41 import android.content.pm.PackageInfo; | 43 import android.content.pm.PackageInfo; | 
| 42 import android.content.pm.PackageManager.NameNotFoundException; | 44 import android.content.pm.PackageManager.NameNotFoundException; | 
| 43 import android.os.Build.VERSION; | 45 import android.os.Build.VERSION; | 
|  | 46 import android.os.Handler; | 
|  | 47 import android.os.Looper; | 
| 44 import android.util.Log; | 48 import android.util.Log; | 
| 45 | 49 | 
| 46 public final class AdblockEngine | 50 public final class AdblockEngine | 
| 47 { | 51 { | 
|  | 52   // default base path to store subscription files in android app | 
|  | 53   public static final String BASE_PATH_DIRECTORY = "adblock"; | 
|  | 54 | 
| 48   private static final String TAG = Utils.getTag(AdblockEngine.class); | 55   private static final String TAG = Utils.getTag(AdblockEngine.class); | 
| 49 | 56 | 
| 50   /* | 57   /* | 
| 51    * The fields below are volatile because: | 58    * The fields below are volatile because: | 
| 52    * | 59    * | 
| 53    * I encountered JNI related bugs/crashes caused by JNI backed Java objects. I
     t seemed that under | 60    * I encountered JNI related bugs/crashes caused by JNI backed Java objects. I
     t seemed that under | 
| 54    * certain conditions the objects were optimized away which resulted in crashe
     s when trying to | 61    * certain conditions the objects were optimized away which resulted in crashe
     s when trying to | 
| 55    * release the object, sometimes even on access. | 62    * release the object, sometimes even on access. | 
| 56    * | 63    * | 
| 57    * The only solution that really worked was to declare the variables holding t
     he references | 64    * The only solution that really worked was to declare the variables holding t
     he references | 
| 58    * volatile, this seems to prevent the JNI from 'optimizing away' those object
     s (as a volatile | 65    * volatile, this seems to prevent the JNI from 'optimizing away' those object
     s (as a volatile | 
| 59    * variable might be changed at any time from any thread). | 66    * variable might be changed at any time from any thread). | 
| 60    */ | 67    */ | 
| 61   private volatile JsEngine jsEngine; | 68   private volatile JsEngine jsEngine; | 
| 62   private volatile FilterEngine filterEngine; | 69   private volatile FilterEngine filterEngine; | 
| 63   private volatile LogSystem logSystem; | 70   private volatile LogSystem logSystem; | 
| 64   private volatile AndroidWebRequest webRequest; | 71   private volatile WebRequest webRequest; | 
| 65   private volatile UpdateAvailableCallback updateAvailableCallback; | 72   private volatile UpdateAvailableCallback updateAvailableCallback; | 
| 66   private volatile UpdateCheckDoneCallback updateCheckDoneCallback; | 73   private volatile UpdateCheckDoneCallback updateCheckDoneCallback; | 
| 67   private volatile FilterChangeCallback filterChangeCallback; | 74   private volatile FilterChangeCallback filterChangeCallback; | 
| 68   private volatile ShowNotificationCallback showNotificationCallback; | 75   private volatile ShowNotificationCallback showNotificationCallback; | 
| 69   private final boolean elemhideEnabled; | 76   private volatile boolean elemhideEnabled; | 
| 70   private volatile boolean enabled = true; | 77   private volatile boolean enabled = true; | 
| 71   private List<String> whitelistedDomains; | 78   private volatile List<String> whitelistedDomains; | 
| 72 |  | 
| 73   private AdblockEngine(final boolean enableElemhide) |  | 
| 74   { |  | 
| 75     this.elemhideEnabled = enableElemhide; |  | 
| 76   } |  | 
| 77 | 79 | 
| 78   public static AppInfo generateAppInfo(final Context context, boolean developme
     ntBuild) | 80   public static AppInfo generateAppInfo(final Context context, boolean developme
     ntBuild) | 
| 79   { | 81   { | 
| 80     String version = "0"; | 82     String version = "0"; | 
| 81     try | 83     try | 
| 82     { | 84     { | 
| 83       final PackageInfo info = context.getPackageManager().getPackageInfo(contex
     t.getPackageName(), 0); | 85       final PackageInfo info = context.getPackageManager().getPackageInfo(contex
     t.getPackageName(), 0); | 
| 84       version = info.versionName; | 86       version = info.versionName; | 
| 85       if (developmentBuild) | 87       if (developmentBuild) | 
| 86         version += "." + info.versionCode; | 88         version += "." + info.versionCode; | 
| 87     } | 89     } | 
| 88     catch (final NameNotFoundException e) | 90     catch (final NameNotFoundException e) | 
| 89     { | 91     { | 
| 90       Log.e(TAG, "Failed to get the application version number", e); | 92       Log.e(TAG, "Failed to get the application version number", e); | 
| 91     } | 93     } | 
| 92     final String sdkVersion = String.valueOf(VERSION.SDK_INT); | 94     final String sdkVersion = String.valueOf(VERSION.SDK_INT); | 
| 93     final String locale = Locale.getDefault().toString().replace('_', '-'); | 95     final String locale = Locale.getDefault().toString().replace('_', '-'); | 
| 94 | 96 | 
| 95     return AppInfo.builder() | 97     return AppInfo.builder() | 
| 96         .setVersion(version) | 98         .setVersion(version) | 
| 97         .setApplicationVersion(sdkVersion) | 99         .setApplicationVersion(sdkVersion) | 
| 98         .setLocale(locale) | 100         .setLocale(locale) | 
| 99         .setDevelopmentBuild(developmentBuild) | 101         .setDevelopmentBuild(developmentBuild) | 
| 100         .build(); | 102         .build(); | 
| 101   } | 103   } | 
| 102 | 104 | 
| 103   public static AdblockEngine create(final AppInfo appInfo, | 105   /** | 
| 104                                      final String basePath, boolean enableElemhi
     de, | 106    * Builds Adblock engine | 
| 105                                      UpdateAvailableCallback updateAvailableCall
     back, | 107    */ | 
| 106                                      UpdateCheckDoneCallback updateCheckDoneCall
     back, | 108   public static class Builder | 
| 107                                      ShowNotificationCallback showNotificationCa
     llback, |  | 
| 108                                      FilterChangeCallback filterChangeCallback) |  | 
| 109   { | 109   { | 
| 110     Log.w(TAG, "Create"); | 110     private Context context; | 
|  | 111     private Map<String, Integer> URLtoResourceIdMap; | 
|  | 112     private AndroidWebRequestResourceWrapper.Storage resourceStorage; | 
|  | 113     private AndroidWebRequest androidWebRequest; | 
|  | 114     private AppInfo appInfo; | 
|  | 115     private String basePath; | 
| 111 | 116 | 
| 112     final AdblockEngine engine = new AdblockEngine(enableElemhide); | 117     private AdblockEngine engine; | 
| 113 | 118 | 
| 114     engine.jsEngine = new JsEngine(appInfo); | 119     protected Builder(final AppInfo appInfo, final String basePath) | 
| 115     engine.jsEngine.setDefaultFileSystem(basePath); | 120     { | 
|  | 121       engine = new AdblockEngine(); | 
|  | 122       engine.elemhideEnabled = true; | 
| 116 | 123 | 
| 117     engine.logSystem = new AndroidLogSystem(); | 124       // we can't create JsEngine and FilterEngine right now as it starts to dow
     nload subscriptions | 
| 118     engine.jsEngine.setLogSystem(engine.logSystem); | 125       // and requests (AndroidWebRequest and probbaly wrappers) are not specifie
     d yet | 
| 119 | 126       this.appInfo = appInfo; | 
| 120     engine.webRequest = new AndroidWebRequest(enableElemhide); | 127       this.basePath = basePath; | 
| 121     engine.jsEngine.setWebRequest(engine.webRequest); |  | 
| 122 |  | 
| 123     engine.filterEngine = new FilterEngine(engine.jsEngine); |  | 
| 124 |  | 
| 125     engine.updateAvailableCallback = updateAvailableCallback; |  | 
| 126     if (engine.updateAvailableCallback != null) |  | 
| 127     { |  | 
| 128       engine.filterEngine.setUpdateAvailableCallback(updateAvailableCallback); |  | 
| 129     } | 128     } | 
| 130 | 129 | 
| 131     engine.updateCheckDoneCallback = updateCheckDoneCallback; | 130     public Builder enableElementHiding(boolean enable) | 
| 132 |  | 
| 133     engine.showNotificationCallback = showNotificationCallback; |  | 
| 134     if (engine.showNotificationCallback != null) |  | 
| 135     { | 131     { | 
| 136       engine.filterEngine.setShowNotificationCallback(showNotificationCallback); | 132       engine.elemhideEnabled = enable; | 
|  | 133       return this; | 
| 137     } | 134     } | 
| 138 | 135 | 
| 139     engine.filterChangeCallback = filterChangeCallback; | 136     public Builder preloadSubscriptions(Context context, | 
| 140     if (engine.filterChangeCallback != null) | 137                                         Map<String, Integer> URLtoResourceIdMap, | 
|  | 138                                         AndroidWebRequestResourceWrapper.Storage
      storage) | 
| 141     { | 139     { | 
| 142       engine.filterEngine.setFilterChangeCallback(filterChangeCallback); | 140       this.context = context; | 
|  | 141       this.URLtoResourceIdMap = URLtoResourceIdMap; | 
|  | 142       this.resourceStorage = storage; | 
|  | 143       return this; | 
| 143     } | 144     } | 
| 144 | 145 | 
| 145     engine.webRequest.updateSubscriptionURLs(engine.filterEngine); | 146     public Builder setUpdateAvailableCallback(UpdateAvailableCallback callback) | 
|  | 147     { | 
|  | 148       engine.updateAvailableCallback = callback; | 
|  | 149       return this; | 
|  | 150     } | 
| 146 | 151 | 
| 147     return engine; | 152     public Builder setUpdateCheckDoneCallback(UpdateCheckDoneCallback callback) | 
|  | 153     { | 
|  | 154       engine.updateCheckDoneCallback = callback; | 
|  | 155       return this; | 
|  | 156     } | 
|  | 157 | 
|  | 158     public Builder setShowNotificationCallback(ShowNotificationCallback callback
     ) | 
|  | 159     { | 
|  | 160       engine.showNotificationCallback = callback; | 
|  | 161       return this; | 
|  | 162     } | 
|  | 163 | 
|  | 164     public Builder setFilterChangeCallback(FilterChangeCallback callback) | 
|  | 165     { | 
|  | 166       engine.filterChangeCallback = callback; | 
|  | 167       return this; | 
|  | 168     } | 
|  | 169 | 
|  | 170     private void initRequests() | 
|  | 171     { | 
|  | 172       androidWebRequest = new AndroidWebRequest(engine.elemhideEnabled); | 
|  | 173       engine.webRequest = androidWebRequest; | 
|  | 174 | 
|  | 175       if (URLtoResourceIdMap != null) | 
|  | 176       { | 
|  | 177         AndroidWebRequestResourceWrapper wrapper = new AndroidWebRequestResource
     Wrapper( | 
|  | 178           context, engine.webRequest, URLtoResourceIdMap, resourceStorage); | 
|  | 179         wrapper.setListener(engine.resourceWrapperListener); | 
|  | 180 | 
|  | 181         engine.webRequest = wrapper; | 
|  | 182       } | 
|  | 183     } | 
|  | 184 | 
|  | 185     private void initCallbacks() | 
|  | 186     { | 
|  | 187       if (engine.updateAvailableCallback != null) | 
|  | 188       { | 
|  | 189         engine.filterEngine.setUpdateAvailableCallback(engine.updateAvailableCal
     lback); | 
|  | 190       } | 
|  | 191 | 
|  | 192       if (engine.showNotificationCallback != null) | 
|  | 193       { | 
|  | 194         engine.filterEngine.setShowNotificationCallback(engine.showNotificationC
     allback); | 
|  | 195       } | 
|  | 196 | 
|  | 197       if (engine.filterChangeCallback != null) | 
|  | 198       { | 
|  | 199         engine.filterEngine.setFilterChangeCallback(engine.filterChangeCallback)
     ; | 
|  | 200       } | 
|  | 201     } | 
|  | 202 | 
|  | 203     public AdblockEngine build() | 
|  | 204     { | 
|  | 205       initRequests(); | 
|  | 206 | 
|  | 207       // webRequest should be ready to be used passed right after JsEngine is cr
     eated | 
|  | 208       createEngines(); | 
|  | 209 | 
|  | 210       initCallbacks(); | 
|  | 211 | 
|  | 212       androidWebRequest.updateSubscriptionURLs(engine.filterEngine); | 
|  | 213 | 
|  | 214       return engine; | 
|  | 215     } | 
|  | 216 | 
|  | 217     private void createEngines() | 
|  | 218     { | 
|  | 219       engine.jsEngine = new JsEngine(appInfo); | 
|  | 220       engine.jsEngine.setDefaultFileSystem(basePath); | 
|  | 221 | 
|  | 222       engine.jsEngine.setWebRequest(engine.webRequest); | 
|  | 223 | 
|  | 224       engine.logSystem = new AndroidLogSystem(); | 
|  | 225       engine.jsEngine.setLogSystem(engine.logSystem); | 
|  | 226 | 
|  | 227       engine.filterEngine = new FilterEngine(engine.jsEngine); | 
|  | 228     } | 
| 148   } | 229   } | 
| 149 | 230 | 
| 150   public static AdblockEngine create(final AppInfo appInfo, | 231   public static Builder builder(AppInfo appInfo, String basePath) | 
| 151                                      final String basePath, boolean elemhideEnab
     led) |  | 
| 152   { | 232   { | 
| 153     return create(appInfo, basePath, elemhideEnabled, null, null, null, null); | 233     return new Builder(appInfo, basePath); | 
| 154   } | 234   } | 
| 155 | 235 | 
|  | 236   private final AndroidWebRequestResourceWrapper.Listener resourceWrapperListene
     r = | 
|  | 237     new AndroidWebRequestResourceWrapper.Listener() | 
|  | 238   { | 
|  | 239     private static final int UPDATE_DELAY_MS = 1 * 1000; | 
|  | 240 | 
|  | 241     private final Handler handler = new Handler(Looper.getMainLooper()); | 
|  | 242 | 
|  | 243     private final Runnable forceUpdateRunnable = new Runnable() | 
|  | 244     { | 
|  | 245       public void run() { | 
|  | 246         // Filter Engine can be already disposed | 
|  | 247         if (filterEngine != null) | 
|  | 248         { | 
|  | 249           Log.d(TAG, "Force update subscriptions"); | 
|  | 250           List<Subscription> subscriptions = filterEngine.getListedSubscriptions
     (); | 
|  | 251           for (Subscription eachSubscription : subscriptions) | 
|  | 252           { | 
|  | 253             try | 
|  | 254             { | 
|  | 255               eachSubscription.updateFilters(); | 
|  | 256             } | 
|  | 257             finally | 
|  | 258             { | 
|  | 259               eachSubscription.dispose(); | 
|  | 260             } | 
|  | 261           } | 
|  | 262         } | 
|  | 263       } | 
|  | 264     }; | 
|  | 265 | 
|  | 266     @Override | 
|  | 267     public void onIntercepted(String url, int resourceId) | 
|  | 268     { | 
|  | 269       // we need to force update subscriptions ASAP after preloaded one is retur
     ned | 
|  | 270       // but we should note that multiple interceptions (for main easylist and A
     A) and force update once only | 
|  | 271 | 
|  | 272       // adding into main thread queue to avoid concurrency issues (start update
      while updating) | 
|  | 273       // as usually onIntercepted() is invoked in background thread | 
|  | 274       handler.removeCallbacks(forceUpdateRunnable); | 
|  | 275       handler.postDelayed(forceUpdateRunnable, UPDATE_DELAY_MS); | 
|  | 276 | 
|  | 277       Log.d(TAG, "Scheduled force update in " + UPDATE_DELAY_MS); | 
|  | 278     } | 
|  | 279   }; | 
|  | 280 | 
| 156   public void dispose() | 281   public void dispose() | 
| 157   { | 282   { | 
| 158     Log.w(TAG, "Dispose"); | 283     Log.w(TAG, "Dispose"); | 
| 159 | 284 | 
| 160     if (this.logSystem != null) | 285     if (this.logSystem != null) | 
| 161     { | 286     { | 
| 162       this.logSystem.dispose(); | 287       this.logSystem.dispose(); | 
| 163       this.logSystem = null; | 288       this.logSystem = null; | 
| 164     } | 289     } | 
| 165 | 290 | 
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 464   public void setWhitelistedDomains(List<String> domains) | 589   public void setWhitelistedDomains(List<String> domains) | 
| 465   { | 590   { | 
| 466     this.whitelistedDomains = domains; | 591     this.whitelistedDomains = domains; | 
| 467   } | 592   } | 
| 468 | 593 | 
| 469   public List<String> getWhitelistedDomains() | 594   public List<String> getWhitelistedDomains() | 
| 470   { | 595   { | 
| 471     return whitelistedDomains; | 596     return whitelistedDomains; | 
| 472   } | 597   } | 
| 473 } | 598 } | 
| OLD | NEW | 
|---|