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-present eyeo GmbH | 3 * Copyright (C) 2006-present 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 package org.adblockplus.libadblockplus.android; |
17 | 18 |
18 package org.adblockplus.libadblockplus.android.settings; | 19 import org.adblockplus.libadblockplus.IsAllowedConnectionCallback; |
19 | 20 |
20 import android.content.Context; | 21 import android.content.Context; |
21 import android.content.SharedPreferences; | 22 import android.content.SharedPreferences; |
22 import android.net.ConnectivityManager; | 23 import android.net.ConnectivityManager; |
23 import android.util.Log; | 24 import android.util.Log; |
24 | 25 |
25 import org.adblockplus.libadblockplus.IsAllowedConnectionCallback; | |
26 import org.adblockplus.libadblockplus.android.AdblockEngine; | |
27 import org.adblockplus.libadblockplus.android.AndroidWebRequestResourceWrapper; | |
28 import org.adblockplus.libadblockplus.android.Utils; | |
29 | |
30 import java.util.Map; | 26 import java.util.Map; |
31 import java.util.concurrent.CountDownLatch; | 27 import java.util.concurrent.CountDownLatch; |
32 import java.util.concurrent.atomic.AtomicInteger; | 28 import java.util.concurrent.atomic.AtomicInteger; |
33 | 29 |
34 /** | 30 /** |
35 * AdblockHelper shared resources | 31 * Provides single instance of AdblockEngine shared between registered clients |
36 * (singleton) | |
37 */ | 32 */ |
38 public class AdblockHelper | 33 public class SingleInstanceEngineProvider implements AdblockEngineProvider |
39 { | 34 { |
40 private static final String TAG = Utils.getTag(AdblockHelper.class); | 35 private static final String TAG = Utils.getTag(SingleInstanceEngineProvider.cl
ass); |
41 | |
42 /** | |
43 * Suggested preference name to store settings | |
44 */ | |
45 public static final String PREFERENCE_NAME = "ADBLOCK"; | |
46 | |
47 /** | |
48 * Suggested preference name to store intercepted subscription requests | |
49 */ | |
50 public static final String PRELOAD_PREFERENCE_NAME = "ADBLOCK_PRELOAD"; | |
51 private static AdblockHelper _instance; | |
52 | 36 |
53 private Context context; | 37 private Context context; |
54 private String basePath; | 38 private String basePath; |
55 private boolean developmentBuild; | 39 private boolean developmentBuild; |
56 private String settingsPreferenceName; | |
57 private String preloadedPreferenceName; | 40 private String preloadedPreferenceName; |
58 private Map<String, Integer> urlToResourceIdMap; | 41 private Map<String, Integer> urlToResourceIdMap; |
59 private AdblockEngine engine; | 42 private AdblockEngine engine; |
60 private AdblockSettingsStorage storage; | |
61 private CountDownLatch engineCreated; | 43 private CountDownLatch engineCreated; |
62 private Long v8IsolateProviderPtr; | 44 private Long v8IsolateProviderPtr; |
| 45 private Runnable engineCreatedCallback; |
| 46 private Runnable engineDisposedCallback; |
63 | 47 |
64 /* | 48 /* |
65 Simple ARC management for AdblockEngine | 49 Simple ARC management for AdblockEngine |
66 Use `retain` and `release` | 50 Use `retain` and `release` |
67 */ | 51 */ |
68 | 52 |
69 private AtomicInteger referenceCounter = new AtomicInteger(0); | 53 private AtomicInteger referenceCounter = new AtomicInteger(0); |
70 | 54 |
71 // singleton | |
72 protected AdblockHelper() | |
73 { | |
74 // prevents instantiation | |
75 } | |
76 | |
77 /** | |
78 * Use to get AdblockHelper instance | |
79 * @return adblock instance | |
80 */ | |
81 public static synchronized AdblockHelper get() | |
82 { | |
83 if (_instance == null) | |
84 { | |
85 _instance = new AdblockHelper(); | |
86 } | |
87 | |
88 return _instance; | |
89 } | |
90 | |
91 public AdblockEngine getEngine() | |
92 { | |
93 return engine; | |
94 } | |
95 | |
96 public AdblockSettingsStorage getStorage() | |
97 { | |
98 return storage; | |
99 } | |
100 | |
101 /** | 55 /** |
102 * Init with context | 56 * Init with context |
103 * @param context application context | 57 * @param context application context |
104 * @param basePath file system root to store files | 58 * @param basePath file system root to store files |
105 * | 59 * |
106 * Adblock Plus library will download subscription files and s
tore them on | 60 * Adblock Plus library will download subscription files and s
tore them on |
107 * the path passed. The path should exist and the directory co
ntent should not be | 61 * the path passed. The path should exist and the directory co
ntent should not be |
108 * cleared out occasionally. Using `context.getCacheDir().getA
bsolutePath()` is not | 62 * cleared out occasionally. Using `context.getCacheDir().getA
bsolutePath()` is not |
109 * recommended because it can be cleared by the system. | 63 * recommended because it can be cleared by the system. |
110 * @param developmentBuild debug or release? | 64 * @param developmentBuild debug or release? |
111 * @param preferenceName Shared Preferences name to store adblock settings | |
112 */ | 65 */ |
113 public AdblockHelper init(Context context, String basePath, | 66 public SingleInstanceEngineProvider(Context context, String basePath, boolean
developmentBuild) |
114 boolean developmentBuild, String preferenceName) | |
115 { | 67 { |
116 this.context = context.getApplicationContext(); | 68 this.context = context.getApplicationContext(); |
117 this.basePath = basePath; | 69 this.basePath = basePath; |
118 this.developmentBuild = developmentBuild; | 70 this.developmentBuild = developmentBuild; |
119 this.settingsPreferenceName = preferenceName; | |
120 return this; | |
121 } | 71 } |
122 | 72 |
123 /** | 73 /** |
124 * Use preloaded subscriptions | 74 * Use preloaded subscriptions |
125 * @param preferenceName Shared Preferences name to store intercepted requests
stats | 75 * @param preferenceName Shared Preferences name to store intercepted requests
stats |
126 * @param urlToResourceIdMap | 76 * @param urlToResourceIdMap |
127 */ | 77 */ |
128 public AdblockHelper preloadSubscriptions(String preferenceName, Map<String, I
nteger> urlToResourceIdMap) | 78 public SingleInstanceEngineProvider preloadSubscriptions(String preferenceName
, |
| 79 Map<String, Integer>
urlToResourceIdMap) |
129 { | 80 { |
130 this.preloadedPreferenceName = preferenceName; | 81 this.preloadedPreferenceName = preferenceName; |
131 this.urlToResourceIdMap = urlToResourceIdMap; | 82 this.urlToResourceIdMap = urlToResourceIdMap; |
132 return this; | 83 return this; |
133 } | 84 } |
134 | 85 |
135 public AdblockHelper useV8IsolateProvider(long ptr) | 86 public SingleInstanceEngineProvider useV8IsolateProvider(long ptr) |
136 { | 87 { |
137 this.v8IsolateProviderPtr = ptr; | 88 this.v8IsolateProviderPtr = ptr; |
138 return this; | 89 return this; |
139 } | 90 } |
140 | 91 |
| 92 public SingleInstanceEngineProvider setEngineCreatedCallback(Runnable callback
) |
| 93 { |
| 94 this.engineCreatedCallback = callback; |
| 95 return this; |
| 96 } |
| 97 |
| 98 public SingleInstanceEngineProvider setEngineDisposedCallback(Runnable callbac
k) |
| 99 { |
| 100 this.engineDisposedCallback = callback; |
| 101 return this; |
| 102 } |
| 103 |
141 private void createAdblock() | 104 private void createAdblock() |
142 { | 105 { |
143 ConnectivityManager connectivityManager = | 106 ConnectivityManager connectivityManager = |
144 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVIC
E); | 107 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVIC
E); |
145 IsAllowedConnectionCallback isAllowedConnectionCallback = new IsAllowedConne
ctionCallbackImpl(connectivityManager); | 108 IsAllowedConnectionCallback isAllowedConnectionCallback = |
| 109 new IsAllowedConnectionCallbackImpl(connectivityManager); |
146 | 110 |
147 Log.d(TAG, "Creating adblock engine ..."); | 111 Log.d(TAG, "Creating adblock engine ..."); |
148 | 112 |
149 // read and apply current settings | |
150 SharedPreferences settingsPrefs = context.getSharedPreferences( | |
151 settingsPreferenceName, | |
152 Context.MODE_PRIVATE); | |
153 storage = new SharedPrefsStorage(settingsPrefs); | |
154 | |
155 AdblockEngine.Builder builder = AdblockEngine | 113 AdblockEngine.Builder builder = AdblockEngine |
156 .builder( | 114 .builder( |
157 AdblockEngine.generateAppInfo(context, developmentBuild), | 115 AdblockEngine.generateAppInfo(context, developmentBuild), |
158 basePath) | 116 basePath) |
159 .setIsAllowedConnectionCallback(isAllowedConnectionCallback) | 117 .setIsAllowedConnectionCallback(isAllowedConnectionCallback) |
160 .enableElementHiding(true); | 118 .enableElementHiding(true); |
161 | 119 |
162 if (v8IsolateProviderPtr != null) | 120 if (v8IsolateProviderPtr != null) |
163 { | 121 { |
164 builder.useV8IsolateProvider(v8IsolateProviderPtr); | 122 builder.useV8IsolateProvider(v8IsolateProviderPtr); |
165 } | 123 } |
166 | 124 |
167 // if preloaded subscriptions provided | 125 // if preloaded subscriptions provided |
168 if (preloadedPreferenceName != null) | 126 if (preloadedPreferenceName != null) |
169 { | 127 { |
170 SharedPreferences preloadedSubscriptionsPrefs = context.getSharedPreferenc
es( | 128 SharedPreferences preloadedSubscriptionsPrefs = context.getSharedPreferenc
es( |
171 preloadedPreferenceName, | 129 preloadedPreferenceName, |
172 Context.MODE_PRIVATE); | 130 Context.MODE_PRIVATE); |
173 builder.preloadSubscriptions( | 131 builder.preloadSubscriptions( |
174 context, | 132 context, |
175 urlToResourceIdMap, | 133 urlToResourceIdMap, |
176 new AndroidWebRequestResourceWrapper.SharedPrefsStorage(preloadedSubscri
ptionsPrefs)); | 134 new AndroidWebRequestResourceWrapper.SharedPrefsStorage(preloadedSubscri
ptionsPrefs)); |
177 } | 135 } |
178 | 136 |
179 engine = builder.build(); | 137 engine = builder.build(); |
180 | 138 |
181 Log.d(TAG, "AdblockHelper engine created"); | 139 Log.d(TAG, "AdblockHelper engine created"); |
182 | 140 |
183 AdblockSettings settings = storage.load(); | 141 // sometimes we need to init AdblockEngine instance, eg. set user settings |
184 if (settings != null) | 142 if (engineCreatedCallback != null) |
185 { | 143 { |
186 Log.d(TAG, "Applying saved adblock settings to adblock engine"); | 144 engineCreatedCallback.run(); |
187 // apply last saved settings to adblock engine | |
188 | |
189 // all the settings except `enabled` and whitelisted domains list | |
190 // are saved by adblock engine itself | |
191 engine.setEnabled(settings.isAdblockEnabled()); | |
192 engine.setWhitelistedDomains(settings.getWhitelistedDomains()); | |
193 | |
194 // allowed connection type is saved by filter engine but we need to overri
de it | |
195 // as filter engine can be not created when changing | |
196 String connectionType = (settings.getAllowedConnectionType() != null | |
197 ? settings.getAllowedConnectionType().getValue() | |
198 : null); | |
199 engine.getFilterEngine().setAllowedConnectionType(connectionType); | |
200 } | |
201 else | |
202 { | |
203 Log.w(TAG, "No saved adblock settings"); | |
204 } | 145 } |
205 } | 146 } |
206 | 147 |
207 /** | 148 @Override |
208 * Wait until everything is ready (used for `retain(true)`) | |
209 * Warning: locks current thread | |
210 */ | |
211 public void waitForReady() | |
212 { | |
213 if (engineCreated == null) | |
214 { | |
215 throw new RuntimeException("AdblockHelper Plus usage exception: call retai
n(true) first"); | |
216 } | |
217 | |
218 try | |
219 { | |
220 Log.d(TAG, "Waiting for ready ..."); | |
221 engineCreated.await(); | |
222 Log.d(TAG, "Ready"); | |
223 } | |
224 catch (InterruptedException e) | |
225 { | |
226 Log.w(TAG, "Interrupted", e); | |
227 } | |
228 } | |
229 | |
230 private void disposeAdblock() | |
231 { | |
232 Log.w(TAG, "Disposing adblock engine"); | |
233 | |
234 engine.dispose(); | |
235 engine = null; | |
236 | |
237 storage = null; | |
238 } | |
239 | |
240 /** | |
241 * Get registered clients count | |
242 * @return registered clients count | |
243 */ | |
244 public int getCounter() | |
245 { | |
246 return referenceCounter.get(); | |
247 } | |
248 | |
249 /** | |
250 * Register AdblockHelper engine client | |
251 * @param asynchronous If `true` engines will be created in background thread
without locking of | |
252 * current thread. Use waitForReady() before getEngine() l
ater. | |
253 * If `false` locks current thread. | |
254 * @return if a new instance is allocated | |
255 */ | |
256 public synchronized boolean retain(boolean asynchronous) | 149 public synchronized boolean retain(boolean asynchronous) |
257 { | 150 { |
258 boolean firstInstance = false; | 151 boolean firstInstance = false; |
259 | 152 |
260 if (referenceCounter.getAndIncrement() == 0) | 153 if (referenceCounter.getAndIncrement() == 0) |
261 { | 154 { |
262 firstInstance = true; | 155 firstInstance = true; |
263 | 156 |
264 if (!asynchronous) | 157 if (!asynchronous) |
265 { | 158 { |
(...skipping 13 matching lines...) Expand all Loading... |
279 | 172 |
280 // unlock waiting client thread | 173 // unlock waiting client thread |
281 engineCreated.countDown(); | 174 engineCreated.countDown(); |
282 } | 175 } |
283 }).start(); | 176 }).start(); |
284 } | 177 } |
285 } | 178 } |
286 return firstInstance; | 179 return firstInstance; |
287 } | 180 } |
288 | 181 |
289 /** | 182 @Override |
290 * Unregister AdblockHelper engine client | 183 public void waitForReady() |
291 * @return `true` if the last instance is destroyed | 184 { |
292 */ | 185 if (engineCreated == null) |
| 186 { |
| 187 throw new IllegalStateException("Usage exception: call retain(true) first"
); |
| 188 } |
| 189 |
| 190 try |
| 191 { |
| 192 Log.d(TAG, "Waiting for ready ..."); |
| 193 engineCreated.await(); |
| 194 Log.d(TAG, "Ready"); |
| 195 } |
| 196 catch (InterruptedException e) |
| 197 { |
| 198 Log.w(TAG, "Interrupted", e); |
| 199 } |
| 200 } |
| 201 |
| 202 @Override |
| 203 public AdblockEngine getEngine() |
| 204 { |
| 205 return engine; |
| 206 } |
| 207 |
| 208 @Override |
293 public synchronized boolean release() | 209 public synchronized boolean release() |
294 { | 210 { |
295 boolean lastInstance = false; | 211 boolean lastInstance = false; |
296 | 212 |
297 if (referenceCounter.decrementAndGet() == 0) | 213 if (referenceCounter.decrementAndGet() == 0) |
298 { | 214 { |
299 lastInstance = true; | 215 lastInstance = true; |
300 | 216 |
301 if (engineCreated != null) | 217 if (engineCreated != null) |
302 { | 218 { |
303 // retained asynchronously | 219 // retained asynchronously |
304 waitForReady(); | 220 waitForReady(); |
305 disposeAdblock(); | 221 disposeAdblock(); |
306 | 222 |
307 // to unlock waiting client in waitForReady() | 223 // to unlock waiting client in waitForReady() |
308 engineCreated.countDown(); | 224 engineCreated.countDown(); |
309 engineCreated = null; | 225 engineCreated = null; |
310 } | 226 } |
311 else | 227 else |
312 { | 228 { |
313 disposeAdblock(); | 229 disposeAdblock(); |
314 } | 230 } |
315 } | 231 } |
316 return lastInstance; | 232 return lastInstance; |
317 } | 233 } |
| 234 |
| 235 private void disposeAdblock() |
| 236 { |
| 237 Log.w(TAG, "Disposing adblock engine"); |
| 238 |
| 239 engine.dispose(); |
| 240 engine = null; |
| 241 |
| 242 // sometimes we need to deinit something after AdblockEngine instance dispos
ed |
| 243 // eg. release user settings |
| 244 if (engineDisposedCallback != null) |
| 245 { |
| 246 engineDisposedCallback.run(); |
| 247 } |
| 248 } |
| 249 |
| 250 @Override |
| 251 public int getCounter() |
| 252 { |
| 253 return referenceCounter.get(); |
| 254 } |
318 } | 255 } |
OLD | NEW |