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: Sergey's comments Created Jan. 22, 2018, 6:19 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 final Runnable engineCreatedCallback = new Runnable()
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.
61 // all the settings except `enabled` and whitelisted domains list
62 // are saved by adblock engine itself
63 provider.getEngine().setEnabled(settings.isAdblockEnabled());
64 provider.getEngine().setWhitelistedDomains(settings.getWhitelistedDomain s());
68 65
69 private AtomicInteger referenceCounter = new AtomicInteger(0); 66 // allowed connection type is saved by filter engine but we need to over ride it
67 // as filter engine can be not created when changing
68 String connectionType = (settings.getAllowedConnectionType() != null
69 ? settings.getAllowedConnectionType().getValue()
70 : null);
71 provider.getEngine().getFilterEngine().setAllowedConnectionType(connecti onType);
72 }
73 else
74 {
75 Log.w(TAG, "No saved adblock settings");
76 }
77 }
78 };
79
80 private final Runnable engineDisposedCallback = new Runnable()
81 {
82 @Override
83 public void run()
84 {
85 Log.d(TAG, "Releasing adblock settings storage");
86 storage = null;
87 }
88 };
70 89
71 // singleton 90 // singleton
72 protected AdblockHelper() 91 protected AdblockHelper()
73 { 92 {
74 // prevents instantiation 93 // prevents instantiation
75 } 94 }
76 95
77 /** 96 /**
78 * Use to get AdblockHelper instance 97 * Use to get AdblockHelper instance
79 * @return adblock instance 98 * @return adblock instance
80 */ 99 */
81 public static synchronized AdblockHelper get() 100 public static synchronized AdblockHelper get()
82 { 101 {
83 if (_instance == null) 102 if (_instance == null)
84 { 103 {
85 _instance = new AdblockHelper(); 104 _instance = new AdblockHelper();
86 } 105 }
87 106
88 return _instance; 107 return _instance;
89 } 108 }
90 109
91 public AdblockEngine getEngine() 110 public AdblockEngineProvider getProvider()
92 { 111 {
93 return engine; 112 if (provider == null)
113 {
114 throw new IllegalStateException("Usage exception: call init(...) first");
115 }
116 return provider;
94 } 117 }
95 118
96 public AdblockSettingsStorage getStorage() 119 public AdblockSettingsStorage getStorage()
97 { 120 {
121 if (storage == null)
122 {
123 throw new IllegalStateException("Usage exception: call init(...) first");
124 }
98 return storage; 125 return storage;
99 } 126 }
100 127
101 /** 128 /**
102 * Init with context 129 * Init with context
103 * @param context application context 130 * @param context application context
104 * @param basePath file system root to store files 131 * @param basePath file system root to store files
105 * 132 *
106 * Adblock Plus library will download subscription files and s tore them on 133 * 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 134 * 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 135 * cleared out occasionally. Using `context.getCacheDir().getA bsolutePath()` is not
109 * recommended because it can be cleared by the system. 136 * recommended because it can be cleared by the system.
110 * @param developmentBuild debug or release? 137 * @param developmentBuild debug or release?
111 * @param preferenceName Shared Preferences name to store adblock settings 138 * @param preferenceName Shared Preferences name to store adblock settings
112 */ 139 */
113 public AdblockHelper init(Context context, String basePath, 140 public SingleInstanceEngineProvider init(Context context, String basePath,
114 boolean developmentBuild, String preferenceName) 141 boolean developmentBuild, String pref erenceName)
115 { 142 {
116 this.context = context.getApplicationContext(); 143 initProvider(context, basePath, developmentBuild);
117 this.basePath = basePath; 144 initStorage(context, preferenceName);
118 this.developmentBuild = developmentBuild; 145 return provider;
119 this.settingsPreferenceName = preferenceName;
120 return this;
121 } 146 }
122 147
123 /** 148 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 { 149 {
130 this.preloadedPreferenceName = preferenceName; 150 provider = new SingleInstanceEngineProvider(context, basePath, developmentBu ild);
131 this.urlToResourceIdMap = urlToResourceIdMap; 151 provider.setEngineCreatedCallback(engineCreatedCallback);
132 return this; 152 provider.setEngineDisposedCallback(engineDisposedCallback);
133 } 153 }
134 154
135 public AdblockHelper useV8IsolateProvider(long ptr) 155 private void initStorage(Context context, String settingsPreferenceName)
136 { 156 {
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 157 // read and apply current settings
150 SharedPreferences settingsPrefs = context.getSharedPreferences( 158 SharedPreferences settingsPrefs = context.getSharedPreferences(
151 settingsPreferenceName, 159 settingsPreferenceName,
152 Context.MODE_PRIVATE); 160 Context.MODE_PRIVATE);
161
153 storage = new SharedPrefsStorage(settingsPrefs); 162 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 } 163 }
206 164
207 /** 165 /**
208 * Wait until everything is ready (used for `retain(true)`) 166 * @deprecated The method is deprecated: use .getProvider().retain() instead
209 * Warning: locks current thread
210 */ 167 */
211 public void waitForReady() 168 @Deprecated
169 public boolean retain(boolean asynchronous)
212 { 170 {
213 if (engineCreated == null) 171 return provider.retain(asynchronous);
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 } 172 }
239 173
240 /** 174 /**
241 * Get registered clients count 175 * @deprecated The method is deprecated: use .getProvider().waitForReady() ins tead
242 * @return registered clients count
243 */ 176 */
244 public int getCounter() 177 @Deprecated
178 public void waitForReady()
245 { 179 {
246 return referenceCounter.get(); 180 provider.waitForReady();
247 } 181 }
248 182
249 /** 183 /**
250 * Register AdblockHelper engine client 184 * @deprecated The method is deprecated: use .getProvider().getEngine() instea d
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 */ 185 */
256 public synchronized boolean retain(boolean asynchronous) 186 @Deprecated
187 public AdblockEngine getEngine()
257 { 188 {
258 boolean firstInstance = false; 189 return provider.getEngine();
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 } 190 }
288 191
289 /** 192 /**
290 * Unregister AdblockHelper engine client 193 * @deprecated The method is deprecated: use .getProvider().release() instead
291 * @return `true` if the last instance is destroyed
292 */ 194 */
293 public synchronized boolean release() 195 @Deprecated
196 public boolean release()
294 { 197 {
295 boolean lastInstance = false; 198 return provider.release();
199 }
296 200
297 if (referenceCounter.decrementAndGet() == 0) 201 /**
298 { 202 * @deprecated The method is deprecated: use .getProvider().getCounter() inste ad
299 lastInstance = true; 203 */
300 204 @Deprecated
301 if (engineCreated != null) 205 public int getCounter()
302 { 206 {
303 // retained asynchronously 207 return provider.getCounter();
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 } 208 }
318 } 209 }
OLDNEW

Powered by Google App Engine
This is Rietveld