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

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

Issue 29671734: Issue 6265 - Create shared AdblockEngine instance in AdblockWebView in background (Closed)
Patch Set: Created Jan. 17, 2018, 11:48 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
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 17
18 package org.adblockplus.libadblockplus.android.settings; 18 package org.adblockplus.libadblockplus.android.settings;
19 19
20 import android.content.Context; 20 import android.content.Context;
21 import android.content.SharedPreferences; 21 import android.content.SharedPreferences;
22 import android.net.ConnectivityManager;
23 import android.util.Log; 22 import android.util.Log;
24 23
25 import org.adblockplus.libadblockplus.IsAllowedConnectionCallback;
26 import org.adblockplus.libadblockplus.android.AdblockEngine; 24 import org.adblockplus.libadblockplus.android.AdblockEngine;
27 import org.adblockplus.libadblockplus.android.AndroidWebRequestResourceWrapper; 25 import org.adblockplus.libadblockplus.android.AdblockEngineProvider;
26 import org.adblockplus.libadblockplus.android.SingleInstanceEngineProvider;
28 import org.adblockplus.libadblockplus.android.Utils; 27 import org.adblockplus.libadblockplus.android.Utils;
29 28
30 import java.util.Map;
31 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.atomic.AtomicInteger;
33
34 /** 29 /**
35 * AdblockHelper shared resources 30 * AdblockHelper shared resources
36 * (singleton) 31 * (singleton)
37 */ 32 */
38 public class AdblockHelper 33 public class AdblockHelper
39 { 34 {
40 private static final String TAG = Utils.getTag(AdblockHelper.class); 35 private static final String TAG = Utils.getTag(AdblockHelper.class);
41 36
42 /** 37 /**
43 * Suggested preference name to store settings 38 * Suggested preference name to store settings
44 */ 39 */
45 public static final String PREFERENCE_NAME = "ADBLOCK"; 40 public static final String PREFERENCE_NAME = "ADBLOCK";
46 41
47 /** 42 /**
48 * Suggested preference name to store intercepted subscription requests 43 * Suggested preference name to store intercepted subscription requests
49 */ 44 */
50 public static final String PRELOAD_PREFERENCE_NAME = "ADBLOCK_PRELOAD"; 45 public static final String PRELOAD_PREFERENCE_NAME = "ADBLOCK_PRELOAD";
51 private static AdblockHelper _instance; 46 private static AdblockHelper _instance;
52 47
53 private Context context; 48 private SingleInstanceEngineProvider provider;
54 private String basePath;
55 private boolean developmentBuild;
56 private String settingsPreferenceName;
57 private String preloadedPreferenceName;
58 private Map<String, Integer> urlToResourceIdMap;
59 private AdblockEngine engine;
60 private AdblockSettingsStorage storage; 49 private AdblockSettingsStorage storage;
61 private CountDownLatch engineCreated;
62 private Long v8IsolateProviderPtr;
63 50
64 /* 51 private Runnable engineCreatedCallback = new Runnable()
diegocarloslima 2018/01/19 12:17:45 maybe declare it final?
anton 2018/01/19 12:27:01 Acknowledged.
65 Simple ARC management for AdblockEngine 52 {
66 Use `retain` and `release` 53 @Override
67 */ 54 public void run()
55 {
56 AdblockSettings settings = storage.load();
57 if (settings != null)
58 {
59 Log.d(TAG, "Applying saved adblock settings to adblock engine");
60 // apply last saved settings to adblock engine
68 61
jens 2018/01/19 09:54:44 Do wen need that empty line?
anton 2018/01/19 10:15:10 it's just [optional] separation between comments (
jens 2018/01/19 10:22:43 I would say that's up to you. I was just not sure
diegocarloslima 2018/01/19 12:17:46 for me it looks a bit weird this new line between
anton 2018/01/19 12:27:01 Acknowledged.
69 private AtomicInteger referenceCounter = new AtomicInteger(0); 62 // all the settings except `enabled` and whitelisted domains list
63 // are saved by adblock engine itself
64 provider.getEngine().setEnabled(settings.isAdblockEnabled());
65 provider.getEngine().setWhitelistedDomains(settings.getWhitelistedDomain s());
66
67 // allowed connection type is saved by filter engine but we need to over ride it
68 // as filter engine can be not created when changing
69 String connectionType = (settings.getAllowedConnectionType() != null
70 ? settings.getAllowedConnectionType().getValue()
71 : null);
72 provider.getEngine().getFilterEngine().setAllowedConnectionType(connecti onType);
73 }
74 else
75 {
76 Log.w(TAG, "No saved adblock settings");
77 }
78 }
79 };
80
81 private Runnable engineDisposedCallback = new Runnable()
diegocarloslima 2018/01/19 12:17:46 maybe declare it final?
anton 2018/01/19 12:27:01 Acknowledged.
82 {
83 @Override
84 public void run()
85 {
86 Log.d(TAG, "Releasing adblock settings storage");
87 storage = null;
88 }
89 };
70 90
71 // singleton 91 // singleton
72 protected AdblockHelper() 92 protected AdblockHelper()
73 { 93 {
74 // prevents instantiation 94 // prevents instantiation
75 } 95 }
76 96
77 /** 97 /**
78 * Use to get AdblockHelper instance 98 * Use to get AdblockHelper instance
79 * @return adblock instance 99 * @return adblock instance
80 */ 100 */
81 public static synchronized AdblockHelper get() 101 public static synchronized AdblockHelper get()
82 { 102 {
83 if (_instance == null) 103 if (_instance == null)
84 { 104 {
85 _instance = new AdblockHelper(); 105 _instance = new AdblockHelper();
86 } 106 }
87 107
88 return _instance; 108 return _instance;
89 } 109 }
90 110
91 public AdblockEngine getEngine() 111 public AdblockEngineProvider getProvider()
92 { 112 {
93 return engine; 113 if (provider == null)
114 {
115 throw new IllegalStateException("Usage exception: call init(...) first");
116 }
117 return provider;
94 } 118 }
95 119
96 public AdblockSettingsStorage getStorage() 120 public AdblockSettingsStorage getStorage()
97 { 121 {
122 if (storage == null)
123 {
124 throw new IllegalStateException("Usage exception: call init(...) first");
125 }
98 return storage; 126 return storage;
99 } 127 }
100 128
101 /** 129 /**
102 * Init with context 130 * Init with context
103 * @param context application context 131 * @param context application context
104 * @param basePath file system root to store files 132 * @param basePath file system root to store files
105 * 133 *
106 * Adblock Plus library will download subscription files and s tore them on 134 * 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 135 * 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 136 * cleared out occasionally. Using `context.getCacheDir().getA bsolutePath()` is not
109 * recommended because it can be cleared by the system. 137 * recommended because it can be cleared by the system.
110 * @param developmentBuild debug or release? 138 * @param developmentBuild debug or release?
111 * @param preferenceName Shared Preferences name to store adblock settings 139 * @param preferenceName Shared Preferences name to store adblock settings
112 */ 140 */
113 public AdblockHelper init(Context context, String basePath, 141 public SingleInstanceEngineProvider init(Context context, String basePath,
114 boolean developmentBuild, String preferenceName) 142 boolean developmentBuild, String pref erenceName)
115 { 143 {
116 this.context = context.getApplicationContext(); 144 initProvider(context, basePath, developmentBuild);
117 this.basePath = basePath; 145 initStorage(context, preferenceName);
118 this.developmentBuild = developmentBuild; 146 return provider;
119 this.settingsPreferenceName = preferenceName;
120 return this;
121 } 147 }
122 148
123 /** 149 private void initProvider(Context context, String basePath, boolean developmen tBuild)
124 * Use preloaded subscriptions
125 * @param preferenceName Shared Preferences name to store intercepted requests stats
126 * @param urlToResourceIdMap
127 */
128 public AdblockHelper preloadSubscriptions(String preferenceName, Map<String, I nteger> urlToResourceIdMap)
129 { 150 {
130 this.preloadedPreferenceName = preferenceName; 151 provider = new SingleInstanceEngineProvider(context, basePath, developmentBu ild);
131 this.urlToResourceIdMap = urlToResourceIdMap; 152 provider.setEngineCreatedCallback(engineCreatedCallback);
132 return this; 153 provider.setEngineDisposedCallback(engineDisposedCallback);
133 } 154 }
134 155
135 public AdblockHelper useV8IsolateProvider(long ptr) 156 private void initStorage(Context context, String settingsPreferenceName)
136 { 157 {
137 this.v8IsolateProviderPtr = ptr;
138 return this;
139 }
140
141 private void createAdblock()
142 {
143 ConnectivityManager connectivityManager =
144 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVIC E);
145 IsAllowedConnectionCallback isAllowedConnectionCallback = new IsAllowedConne ctionCallbackImpl(connectivityManager);
146
147 Log.d(TAG, "Creating adblock engine ...");
148
149 // read and apply current settings 158 // read and apply current settings
150 SharedPreferences settingsPrefs = context.getSharedPreferences( 159 SharedPreferences settingsPrefs = context.getSharedPreferences(
151 settingsPreferenceName, 160 settingsPreferenceName,
152 Context.MODE_PRIVATE); 161 Context.MODE_PRIVATE);
162
153 storage = new SharedPrefsStorage(settingsPrefs); 163 storage = new SharedPrefsStorage(settingsPrefs);
154
155 AdblockEngine.Builder builder = AdblockEngine
156 .builder(
157 AdblockEngine.generateAppInfo(context, developmentBuild),
158 basePath)
159 .setIsAllowedConnectionCallback(isAllowedConnectionCallback)
160 .enableElementHiding(true);
161
162 if (v8IsolateProviderPtr != null)
163 {
164 builder.useV8IsolateProvider(v8IsolateProviderPtr);
165 }
166
167 // if preloaded subscriptions provided
168 if (preloadedPreferenceName != null)
169 {
170 SharedPreferences preloadedSubscriptionsPrefs = context.getSharedPreferenc es(
171 preloadedPreferenceName,
172 Context.MODE_PRIVATE);
173 builder.preloadSubscriptions(
174 context,
175 urlToResourceIdMap,
176 new AndroidWebRequestResourceWrapper.SharedPrefsStorage(preloadedSubscri ptionsPrefs));
177 }
178
179 engine = builder.build();
180
181 Log.d(TAG, "AdblockHelper engine created");
182
183 AdblockSettings settings = storage.load();
184 if (settings != null)
185 {
186 Log.d(TAG, "Applying saved adblock settings to adblock engine");
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 }
205 } 164 }
206 165
207 /** 166 // The methods below are deprecated: use .getProvider().method() instead
diegocarloslima 2018/01/19 12:17:45 This comment would be better inside the javadoc pa
anton 2018/01/19 12:27:01 Acknowledged.
208 * Wait until everything is ready (used for `retain(true)`) 167
209 * Warning: locks current thread 168 @Deprecated
210 */ 169 public boolean retain(boolean asynchronous)
170 {
171 return provider.retain(asynchronous);
172 }
173
174 @Deprecated
211 public void waitForReady() 175 public void waitForReady()
212 { 176 {
213 if (engineCreated == null) 177 provider.waitForReady();
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 } 178 }
229 179
230 private void disposeAdblock() 180 @Deprecated
181 public AdblockEngine getEngine()
231 { 182 {
232 Log.w(TAG, "Disposing adblock engine"); 183 return provider.getEngine();
233
234 engine.dispose();
235 engine = null;
236
237 storage = null;
238 } 184 }
239 185
240 /** 186 @Deprecated
241 * Get registered clients count 187 public boolean release()
242 * @return registered clients count 188 {
243 */ 189 return provider.release();
190 }
191
192 @Deprecated
244 public int getCounter() 193 public int getCounter()
245 { 194 {
246 return referenceCounter.get(); 195 return provider.getCounter();
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)
257 {
258 boolean firstInstance = false;
259
260 if (referenceCounter.getAndIncrement() == 0)
261 {
262 firstInstance = true;
263
264 if (!asynchronous)
265 {
266 createAdblock();
267 }
268 else
269 {
270 // latch is required for async (see `waitForReady()`)
271 engineCreated = new CountDownLatch(1);
272
273 new Thread(new Runnable()
274 {
275 @Override
276 public void run()
277 {
278 createAdblock();
279
280 // unlock waiting client thread
281 engineCreated.countDown();
282 }
283 }).start();
284 }
285 }
286 return firstInstance;
287 }
288
289 /**
290 * Unregister AdblockHelper engine client
291 * @return `true` if the last instance is destroyed
292 */
293 public synchronized boolean release()
294 {
295 boolean lastInstance = false;
296
297 if (referenceCounter.decrementAndGet() == 0)
298 {
299 lastInstance = true;
300
301 if (engineCreated != null)
302 {
303 // retained asynchronously
304 waitForReady();
305 disposeAdblock();
306
307 // to unlock waiting client in waitForReady()
308 engineCreated.countDown();
309 engineCreated = null;
310 }
311 else
312 {
313 disposeAdblock();
314 }
315 }
316 return lastInstance;
317 } 196 }
318 } 197 }
OLDNEW

Powered by Google App Engine
This is Rietveld