Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: libadblockplus-android/src/org/adblockplus/libadblockplus/android/AdblockEngine.java

Issue 29678581: Issue 6000 - Rename "libadblockplus-android" (Closed)
Patch Set: Created Jan. 24, 2018, 6:53 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH
4 *
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
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
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/>.
16 */
17
18 package org.adblockplus.libadblockplus.android;
19
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Locale;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.adblockplus.libadblockplus.AppInfo;
30 import org.adblockplus.libadblockplus.Filter;
31 import org.adblockplus.libadblockplus.FilterChangeCallback;
32 import org.adblockplus.libadblockplus.FilterEngine;
33 import org.adblockplus.libadblockplus.FilterEngine.ContentType;
34 import org.adblockplus.libadblockplus.IsAllowedConnectionCallback;
35 import org.adblockplus.libadblockplus.JsValue;
36 import org.adblockplus.libadblockplus.LogSystem;
37 import org.adblockplus.libadblockplus.Platform;
38 import org.adblockplus.libadblockplus.ShowNotificationCallback;
39 import org.adblockplus.libadblockplus.Subscription;
40 import org.adblockplus.libadblockplus.UpdateAvailableCallback;
41 import org.adblockplus.libadblockplus.UpdateCheckDoneCallback;
42 import org.adblockplus.libadblockplus.WebRequest;
43
44 import android.content.Context;
45 import android.content.pm.PackageInfo;
46 import android.content.pm.PackageManager;
47 import android.os.Build.VERSION;
48 import android.util.Log;
49
50 public final class AdblockEngine
51 {
52 // default base path to store subscription files in android app
53 public static final String BASE_PATH_DIRECTORY = "adblock";
54
55 private static final String TAG = Utils.getTag(AdblockEngine.class);
56
57 /*
58 * The fields below are volatile because:
59 *
60 * I encountered JNI related bugs/crashes caused by JNI backed Java objects. I t seemed that under
61 * certain conditions the objects were optimized away which resulted in crashe s when trying to
62 * release the object, sometimes even on access.
63 *
64 * The only solution that really worked was to declare the variables holding t he references
65 * volatile, this seems to prevent the JNI from 'optimizing away' those object s (as a volatile
66 * variable might be changed at any time from any thread).
67 */
68 private volatile Platform platform;
69 private volatile FilterEngine filterEngine;
70 private volatile LogSystem logSystem;
71 private volatile WebRequest webRequest;
72 private volatile UpdateAvailableCallback updateAvailableCallback;
73 private volatile UpdateCheckDoneCallback updateCheckDoneCallback;
74 private volatile FilterChangeCallback filterChangeCallback;
75 private volatile ShowNotificationCallback showNotificationCallback;
76 private volatile boolean elemhideEnabled;
77 private volatile boolean enabled = true;
78 private volatile List<String> whitelistedDomains;
79
80 public static AppInfo generateAppInfo(final Context context, boolean developme ntBuild,
81 String application, String applicationVe rsion)
82 {
83 final String sdkVersion = String.valueOf(VERSION.SDK_INT);
84 final String locale = Locale.getDefault().toString().replace('_', '-');
85
86 AppInfo.Builder builder =
87 AppInfo
88 .builder()
89 .setApplicationVersion(sdkVersion)
90 .setLocale(locale)
91 .setDevelopmentBuild(developmentBuild);
92
93 if (application != null)
94 {
95 builder.setApplication(application);
96 }
97
98 if (applicationVersion != null)
99 {
100 builder.setApplicationVersion(applicationVersion);
101 }
102
103 return builder.build();
104 }
105
106 public static AppInfo generateAppInfo(final Context context, boolean developme ntBuild)
107 {
108 try
109 {
110 PackageInfo packageInfo = context.getPackageManager().getPackageInfo(conte xt.getPackageName(), 0);
111 String application = context.getPackageName();
112 String applicationVersion = packageInfo.versionName;
113
114 return generateAppInfo(context, developmentBuild, application, application Version);
115 }
116 catch (PackageManager.NameNotFoundException e)
117 {
118 throw new RuntimeException(e);
119 }
120 }
121
122 /**
123 * Builds Adblock engine
124 */
125 public static class Builder
126 {
127 private Context context;
128 private Map<String, Integer> urlToResourceIdMap;
129 private AndroidWebRequestResourceWrapper.Storage resourceStorage;
130 private AndroidWebRequest androidWebRequest;
131 private AppInfo appInfo;
132 private String basePath;
133 private IsAllowedConnectionCallback isAllowedConnectionCallback;
134 private Long v8IsolateProviderPtr;
135
136 private AdblockEngine engine;
137
138 protected Builder(final AppInfo appInfo, final String basePath)
139 {
140 engine = new AdblockEngine();
141 engine.elemhideEnabled = true;
142
143 // we can't create JsEngine and FilterEngine right now as it starts to dow nload subscriptions
144 // and requests (AndroidWebRequest and probbaly wrappers) are not specifie d yet
145 this.appInfo = appInfo;
146 this.basePath = basePath;
147 }
148
149 public Builder enableElementHiding(boolean enable)
150 {
151 engine.elemhideEnabled = enable;
152 return this;
153 }
154
155 public Builder preloadSubscriptions(Context context,
156 Map<String, Integer> urlToResourceIdMap,
157 AndroidWebRequestResourceWrapper.Storage storage)
158 {
159 this.context = context;
160 this.urlToResourceIdMap = urlToResourceIdMap;
161 this.resourceStorage = storage;
162 return this;
163 }
164
165 public Builder setIsAllowedConnectionCallback(IsAllowedConnectionCallback ca llback)
166 {
167 this.isAllowedConnectionCallback = callback;
168 return this;
169 }
170
171 public Builder useV8IsolateProvider(long v8IsolateProviderPtr)
172 {
173 this.v8IsolateProviderPtr = v8IsolateProviderPtr;
174 return this;
175 }
176
177 public Builder setUpdateAvailableCallback(UpdateAvailableCallback callback)
178 {
179 engine.updateAvailableCallback = callback;
180 return this;
181 }
182
183 public Builder setUpdateCheckDoneCallback(UpdateCheckDoneCallback callback)
184 {
185 engine.updateCheckDoneCallback = callback;
186 return this;
187 }
188
189 public Builder setShowNotificationCallback(ShowNotificationCallback callback )
190 {
191 engine.showNotificationCallback = callback;
192 return this;
193 }
194
195 public Builder setFilterChangeCallback(FilterChangeCallback callback)
196 {
197 engine.filterChangeCallback = callback;
198 return this;
199 }
200
201 private void initRequests()
202 {
203 androidWebRequest = new AndroidWebRequest(engine.elemhideEnabled, true);
204 engine.webRequest = androidWebRequest;
205
206 if (urlToResourceIdMap != null)
207 {
208 AndroidWebRequestResourceWrapper wrapper = new AndroidWebRequestResource Wrapper(
209 context, engine.webRequest, urlToResourceIdMap, resourceStorage);
210 wrapper.setListener(new AndroidWebRequestResourceWrapper.Listener()
211 {
212 @Override
213 public void onIntercepted(String url, int resourceId)
214 {
215 Log.d(TAG, "Force subscription update for intercepted URL " + url);
216 if (engine.filterEngine != null)
217 {
218 engine.filterEngine.updateFiltersAsync(url);
219 }
220 }
221 });
222
223 engine.webRequest = wrapper;
224 }
225 }
226
227 private void initCallbacks()
228 {
229 if (engine.updateAvailableCallback != null)
230 {
231 engine.filterEngine.setUpdateAvailableCallback(engine.updateAvailableCal lback);
232 }
233
234 if (engine.showNotificationCallback != null)
235 {
236 engine.filterEngine.setShowNotificationCallback(engine.showNotificationC allback);
237 }
238
239 if (engine.filterChangeCallback != null)
240 {
241 engine.filterEngine.setFilterChangeCallback(engine.filterChangeCallback) ;
242 }
243 }
244
245 public AdblockEngine build()
246 {
247 initRequests();
248
249 // webRequest should be ready to be used passed right after JsEngine is cr eated
250 createEngines();
251
252 initCallbacks();
253
254 if (!engine.elemhideEnabled)
255 {
256 androidWebRequest.updateSubscriptionURLs(engine.filterEngine);
257 }
258
259 return engine;
260 }
261
262 private void createEngines()
263 {
264 engine.logSystem = new AndroidLogSystem();
265 engine.platform = new Platform(engine.logSystem, engine.webRequest, basePa th);
266 if (v8IsolateProviderPtr != null)
267 {
268 engine.platform.setUpJsEngine(appInfo, v8IsolateProviderPtr);
269 }
270 else
271 {
272 engine.platform.setUpJsEngine(appInfo);
273 }
274 engine.platform.setUpFilterEngine(isAllowedConnectionCallback);
275 engine.filterEngine = engine.platform.getFilterEngine();
276 }
277 }
278
279 public static Builder builder(AppInfo appInfo, String basePath)
280 {
281 return new Builder(appInfo, basePath);
282 }
283
284 public void dispose()
285 {
286 Log.w(TAG, "Dispose");
287
288 // engines first
289 if (this.filterEngine != null)
290 {
291 if (this.updateAvailableCallback != null)
292 {
293 this.filterEngine.removeUpdateAvailableCallback();
294 }
295
296 if (this.filterChangeCallback != null)
297 {
298 this.filterEngine.removeFilterChangeCallback();
299 }
300
301 if (this.showNotificationCallback != null)
302 {
303 this.filterEngine.removeShowNotificationCallback();
304 }
305
306 this.platform.dispose();
307 this.platform = null;
308 }
309
310 // callbacks then
311 if (this.updateAvailableCallback != null)
312 {
313 this.updateAvailableCallback.dispose();
314 this.updateAvailableCallback = null;
315 }
316
317 if (this.filterChangeCallback != null)
318 {
319 this.filterChangeCallback.dispose();
320 this.filterChangeCallback = null;
321 }
322
323 if (this.showNotificationCallback != null)
324 {
325 this.showNotificationCallback.dispose();
326 this.showNotificationCallback = null;
327 }
328 }
329
330 public boolean isFirstRun()
331 {
332 return this.filterEngine.isFirstRun();
333 }
334
335 public boolean isElemhideEnabled()
336 {
337 return this.elemhideEnabled;
338 }
339
340 private static org.adblockplus.libadblockplus.android.Subscription convertJsSu bscription(final Subscription jsSubscription)
341 {
342 final org.adblockplus.libadblockplus.android.Subscription subscription =
343 new org.adblockplus.libadblockplus.android.Subscription();
344
345 JsValue jsTitle = jsSubscription.getProperty("title");
346 try
347 {
348 subscription.title = jsTitle.toString();
349 }
350 finally
351 {
352 jsTitle.dispose();
353 }
354
355 JsValue jsUrl = jsSubscription.getProperty("url");
356 try
357 {
358 subscription.url = jsUrl.toString();
359 }
360 finally
361 {
362 jsUrl.dispose();
363 }
364
365 JsValue jsSpecialization = jsSubscription.getProperty("specialization");
366 try
367 {
368 subscription.specialization = jsSpecialization.toString();
369 }
370 finally
371 {
372 jsSpecialization.dispose();
373 }
374
375 return subscription;
376 }
377
378 private static org.adblockplus.libadblockplus.android.Subscription[] convertJs Subscriptions(
379 final List<Subscription> jsSubscriptions)
380 {
381 final org.adblockplus.libadblockplus.android.Subscription[] subscriptions =
382 new org.adblockplus.libadblockplus.android.Subscription[jsSubscriptions.si ze()];
383
384 for (int i = 0; i < subscriptions.length; i++)
385 {
386 subscriptions[i] = convertJsSubscription(jsSubscriptions.get(i));
387 }
388
389 return subscriptions;
390 }
391
392 public org.adblockplus.libadblockplus.android.Subscription[] getRecommendedSub scriptions()
393 {
394 List<Subscription> subscriptions = this.filterEngine.fetchAvailableSubscript ions();
395 try
396 {
397 return convertJsSubscriptions(subscriptions);
398 }
399 finally
400 {
401 for (Subscription eachSubscription : subscriptions)
402 {
403 eachSubscription.dispose();
404 }
405 }
406 }
407
408 public org.adblockplus.libadblockplus.android.Subscription[] getListedSubscrip tions()
409 {
410 List<Subscription> subscriptions = this.filterEngine.getListedSubscriptions( );
411 try
412 {
413 return convertJsSubscriptions(subscriptions);
414 }
415 finally
416 {
417 for (Subscription eachSubscription : subscriptions)
418 {
419 eachSubscription.dispose();
420 }
421 }
422 }
423
424 public void clearSubscriptions()
425 {
426 for (final Subscription s : this.filterEngine.getListedSubscriptions())
427 {
428 try
429 {
430 s.removeFromList();
431 }
432 finally
433 {
434 s.dispose();
435 }
436 }
437 }
438
439 public void setSubscription(final String url)
440 {
441 clearSubscriptions();
442
443 final Subscription sub = this.filterEngine.getSubscription(url);
444 if (sub != null)
445 {
446 try
447 {
448 sub.addToList();
449 }
450 finally
451 {
452 sub.dispose();
453 }
454 }
455 }
456
457 public void setSubscriptions(Collection<String> urls)
458 {
459 clearSubscriptions();
460
461 for (String eachUrl : urls)
462 {
463 final Subscription sub = this.filterEngine.getSubscription(eachUrl);
464 if (sub != null)
465 {
466 try
467 {
468 sub.addToList();
469 }
470 finally
471 {
472 sub.dispose();
473 }
474 }
475 }
476 }
477
478 public void setEnabled(final boolean enabled)
479 {
480 this.enabled = enabled;
481 }
482
483 public boolean isEnabled()
484 {
485 return enabled;
486 }
487
488 public String getAcceptableAdsSubscriptionURL()
489 {
490 return filterEngine.getAcceptableAdsSubscriptionURL();
491 }
492
493 public boolean isAcceptableAdsEnabled()
494 {
495 return filterEngine.isAcceptableAdsEnabled();
496 }
497
498 public void setAcceptableAdsEnabled(final boolean enabled)
499 {
500 filterEngine.setAcceptableAdsEnabled(enabled);
501 }
502
503 public String getDocumentationLink()
504 {
505 JsValue jsPref = this.filterEngine.getPref("documentation_link");
506 try
507 {
508 return jsPref.toString();
509 }
510 finally
511 {
512 jsPref.dispose();
513 }
514 }
515
516 public boolean matches(final String fullUrl, final ContentType contentType, fi nal String[] referrerChainArray)
517 {
518 if (!enabled)
519 {
520 return false;
521 }
522
523 final Filter filter = this.filterEngine.matches(fullUrl, contentType, referr erChainArray);
524
525 if (filter == null)
526 {
527 return false;
528 }
529
530 try
531 {
532 // hack: if there is no referrer, block only if filter is domain-specific
533 // (to re-enable in-app ads blocking, proposed on 12.11.2012 Monday meetin g)
534 // (documentUrls contains the referrers on Android)
535 try
536 {
537 JsValue jsText = filter.getProperty("text");
538 try
539 {
540 if (referrerChainArray.length == 0 && (jsText.toString()).contains("|| "))
541 {
542 return false;
543 }
544 }
545 finally
546 {
547 jsText.dispose();
548 }
549 }
550 catch (NullPointerException e)
551 {
552 }
553
554 return filter.getType() != Filter.Type.EXCEPTION;
555 }
556 finally
557 {
558 filter.dispose();
559 }
560 }
561
562 public boolean isDocumentWhitelisted(final String url, final String[] referrer ChainArray)
563 {
564 return this.filterEngine.isDocumentWhitelisted(url, referrerChainArray);
565 }
566
567 public boolean isDomainWhitelisted(final String url, final String[] referrerCh ainArray)
568 {
569 if (whitelistedDomains == null)
570 {
571 return false;
572 }
573
574 // using Set to remove duplicates
575 Set<String> referrersAndResourceUrls = new HashSet<String>();
576 if (referrerChainArray != null)
577 {
578 referrersAndResourceUrls.addAll(Arrays.asList(referrerChainArray));
579 }
580 referrersAndResourceUrls.add(url);
581
582 for (String eachUrl : referrersAndResourceUrls)
583 {
584 if (whitelistedDomains.contains(filterEngine.getHostFromURL(eachUrl)))
585 {
586 return true;
587 }
588 }
589
590 return false;
591 }
592
593 public boolean isElemhideWhitelisted(final String url, final String[] referrer ChainArray)
594 {
595 return this.filterEngine.isElemhideWhitelisted(url, referrerChainArray);
596 }
597
598 public List<String> getElementHidingSelectors(final String url, final String d omain, final String[] referrerChainArray)
599 {
600 /*
601 * Issue 3364 (https://issues.adblockplus.org/ticket/3364) introduced the
602 * feature to re-enabled element hiding.
603 *
604 * Nothing changes for Adblock Plus for Android, as `this.elemhideEnabled`
605 * is `false`, which results in an empty list being returned and converted
606 * into a `(String[])null` in AdblockPlus.java, which is the only place
607 * this function here is called from Adblock Plus for Android.
608 *
609 * If element hiding is enabled, then this function now first checks for
610 * possible whitelisting of either the document or element hiding for
611 * the given URL and returns an empty list if so. This is needed to
612 * ensure correct functioning of e.g. acceptable ads.
613 */
614 if (!this.enabled
615 || !this.elemhideEnabled
616 || this.isDomainWhitelisted(url, referrerChainArray)
617 || this.isDocumentWhitelisted(url, referrerChainArray)
618 || this.isElemhideWhitelisted(url, referrerChainArray))
619 {
620 return new ArrayList<String>();
621 }
622 return this.filterEngine.getElementHidingSelectors(domain);
623 }
624
625 public void checkForUpdates()
626 {
627 this.filterEngine.forceUpdateCheck(this.updateCheckDoneCallback);
628 }
629
630 public FilterEngine getFilterEngine()
631 {
632 return this.filterEngine;
633 }
634
635 public void setWhitelistedDomains(List<String> domains)
636 {
637 this.whitelistedDomains = domains;
638 }
639
640 public List<String> getWhitelistedDomains()
641 {
642 return whitelistedDomains;
643 }
644 }
OLDNEW

Powered by Google App Engine
This is Rietveld