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

Side by Side Diff: src/org/adblockplus/android/ProxyService.java

Issue 4705284891082752: Proxy configurators (Closed)
Patch Set: valueOf Created Aug. 19, 2014, 1:24 p.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 <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2014 Eyeo GmbH 3 * Copyright (C) 2006-2014 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.android; 18 package org.adblockplus.android;
19 19
20 import java.io.File;
21 import java.io.FileNotFoundException;
22 import java.io.IOException; 20 import java.io.IOException;
23 import java.lang.reflect.Method;
24 import java.net.InetAddress; 21 import java.net.InetAddress;
25 import java.net.ServerSocket; 22 import java.net.ServerSocket;
26 import java.util.List; 23 import java.net.UnknownHostException;
27 import java.util.Properties; 24 import java.util.Properties;
28 import java.util.concurrent.TimeoutException; 25
26 import org.adblockplus.android.configurators.ProxyConfigurator;
27 import org.adblockplus.android.configurators.ProxyConfigurators;
28 import org.adblockplus.android.configurators.ProxyRegistrationType;
29 import org.apache.commons.lang.StringUtils;
29 30
30 import sunlabs.brazil.server.Server; 31 import sunlabs.brazil.server.Server;
31 import sunlabs.brazil.util.Base64; 32 import sunlabs.brazil.util.Base64;
32 import android.annotation.SuppressLint; 33 import android.annotation.SuppressLint;
33 import android.app.Notification; 34 import android.app.Notification;
34 import android.app.NotificationManager; 35 import android.app.NotificationManager;
35 import android.app.PendingIntent; 36 import android.app.PendingIntent;
36 import android.app.Service; 37 import android.app.Service;
37 import android.content.BroadcastReceiver; 38 import android.content.BroadcastReceiver;
38 import android.content.Context; 39 import android.content.Context;
39 import android.content.Intent; 40 import android.content.Intent;
40 import android.content.IntentFilter; 41 import android.content.IntentFilter;
41 import android.content.SharedPreferences; 42 import android.content.SharedPreferences;
42 import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 43 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
43 import android.content.pm.PackageManager.NameNotFoundException;
44 import android.content.res.Resources;
45 import android.net.ConnectivityManager;
46 import android.net.NetworkInfo;
47 import android.net.Proxy;
48 import android.os.Binder; 44 import android.os.Binder;
49 import android.os.Build; 45 import android.os.Build;
50 import android.os.Handler;
51 import android.os.IBinder; 46 import android.os.IBinder;
52 import android.os.StrictMode; 47 import android.os.StrictMode;
53 import android.preference.PreferenceManager; 48 import android.preference.PreferenceManager;
54 import android.support.v4.app.NotificationCompat; 49 import android.support.v4.app.NotificationCompat;
55 import android.util.Log; 50 import android.util.Log;
56 51
57 import com.stericson.RootTools.RootTools;
58 import com.stericson.RootTools.RootToolsException;
59
60 public class ProxyService extends Service implements OnSharedPreferenceChangeLis tener 52 public class ProxyService extends Service implements OnSharedPreferenceChangeLis tener
61 { 53 {
54 private static final String TAG = Utils.getTag(ProxyService.class);
55
62 private static final String LOCALHOST = "127.0.0.1"; 56 private static final String LOCALHOST = "127.0.0.1";
63 /**
64 * Indicates that system supports native proxy configuration.
65 */
66 public static final boolean NATIVE_PROXY_SUPPORTED = Build.VERSION.SDK_INT >= 12; // Honeycomb 3.1
67 57
68 static 58 private static final int[] PORT_VARIANTS = new int[] {-1, 2020, 3030, 4040, 50 50, 6060, 7070, 9090, 1234, 12345, 4321, 0};
69 {
70 RootTools.debugMode = false;
71 }
72 59
73 private static final String TAG = Utils.getTag(ProxyService.class); 60 private static final boolean LOG_REQUESTS = false;
74 private static final boolean logRequests = false;
75
76 // Do not use 8080 because it is a "dirty" port, Android uses it if something goes wrong
77 // first element is reserved for previously used port
78 private static final int[] portVariants = new int[] {-1, 2020, 3030, 4040, 505 0, 6060, 7070, 9090, 1234, 12345, 4321, 0};
79
80 private static final int DEFAULT_TIMEOUT = 3000;
81 private static final int NO_TRAFFIC_TIMEOUT = 5 * 60 * 1000; // 5 minutes
82 61
83 static final int ONGOING_NOTIFICATION_ID = R.string.app_name; 62 static final int ONGOING_NOTIFICATION_ID = R.string.app_name;
63
84 private static final long POSITION_RIGHT = Build.VERSION.SDK_INT >= Build.VERS ION_CODES.GINGERBREAD ? Long.MIN_VALUE : Long.MAX_VALUE; 64 private static final long POSITION_RIGHT = Build.VERSION.SDK_INT >= Build.VERS ION_CODES.GINGERBREAD ? Long.MIN_VALUE : Long.MAX_VALUE;
85 private static final int NOTRAFFIC_NOTIFICATION_ID = R.string.app_name + 3;
86 65
87 /** 66 /**
88 * Broadcasted when service starts or stops. 67 * Broadcasted when service starts or stops.
89 */ 68 */
90 public static final String BROADCAST_STATE_CHANGED = "org.adblockplus.android. service.state"; 69 public static final String BROADCAST_STATE_CHANGED = "org.adblockplus.android. SERVICE_STATE_CHANGED";
70
91 /** 71 /**
92 * Broadcasted if proxy fails to start. 72 * Broadcasted if proxy fails to start.
93 */ 73 */
94 public static final String BROADCAST_PROXY_FAILED = "org.adblockplus.android.p roxy.failure"; 74 public static final String BROADCAST_PROXY_FAILED = "org.adblockplus.android.P ROXY_FAILURE";
95 75
96 private static final String IPTABLES_RETURN = " -t nat -m owner --uid-owner {{ UID}} -A OUTPUT -p tcp -j RETURN\n"; 76 /**
97 private static final String IPTABLES_ADD_HTTP = " -t nat -A OUTPUT -p tcp --dp ort 80 -j REDIRECT --to {{PORT}}\n"; 77 * Common command bridge
78 */
79 public static final String COMMAND_BRIDGE_ACTION = "org.adblockplus.android.CO MMAND_BRIDGE";
98 80
99 boolean hideIcon; 81 boolean hideIcon;
100 private Handler notrafficHandler;
101 82
102 protected ProxyServer proxy = null; 83 protected ProxyServer proxy = null;
84
103 protected int port; 85 protected int port;
86
104 private final Properties proxyConfiguration = new Properties(); 87 private final Properties proxyConfiguration = new Properties();
105 88
106 /** 89 private ProxyConfigurator proxyConfigurator = null;
107 * Indicates that service is working with root privileges.
108 */
109 private boolean transparent = false;
110 /**
111 * Indicates that service has autoconfigured Android proxy settings (version 3 .1+).
112 */
113 private boolean nativeProxyAutoConfigured = false;
114 /**
115 * Indicates that Android proxy settings are correctly configured (version 4.1 .2+ 4.2.2+).
116 */
117 private boolean proxyManualyConfigured = false;
118
119 private String iptables = null;
120 90
121 @SuppressLint("NewApi") 91 @SuppressLint("NewApi")
122 @Override 92 @Override
123 public void onCreate() 93 public void onCreate()
124 { 94 {
125 super.onCreate(); 95 super.onCreate();
126 96
127 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) 97 // FIXME 'StrictMode' is API9
Felix Dahlke 2014/08/19 16:14:46 I still think this should be part of a larger "sup
René Jeschke 2014/08/19 16:33:24 We talked about this some weeks ago. I told you th
128 { 98 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
129 // Proxy is running in separate thread, it's just some resolution request during initialization. 99 .permitAll()
130 // Not worth spawning a separate thread for this. 100 .penaltyLog()
131 final StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder ().permitNetwork().build(); 101 .build());
132 StrictMode.setThreadPolicy(policy);
133 }
134 102
135 // Get port for local proxy
136 final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreference s(this); 103 final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreference s(this);
137 final Resources resources = getResources();
138 104
139 // Try to read user proxy settings 105 // Try to read user proxy settings
140 String proxyHost = null; 106 String proxyHost = System.getProperty("http.proxyHost");;
141 String proxyPort = null; 107 String proxyPort = System.getProperty("http.proxyPort");
142 String proxyExcl = null; 108 final String proxyExcl = System.getProperty("http.nonProxyHosts");
143 String proxyUser = null; 109 String proxyUser = null;
144 String proxyPass = null; 110 String proxyPass = null;
145 111
146 if (NATIVE_PROXY_SUPPORTED) 112 if (proxyHost == null || proxyPort == null)
147 {
148 // Read system settings
149 proxyHost = System.getProperty("http.proxyHost");
150 proxyPort = System.getProperty("http.proxyPort");
151 proxyExcl = System.getProperty("http.nonProxyHosts");
152
153 Log.d(TAG, "PRX: " + proxyHost + ":" + proxyPort + "(" + proxyExcl + ")");
154 // not used but left for future reference
155 final String[] px = ProxySettings.getUserProxy(getApplicationContext());
156 if (px != null)
157 Log.d(TAG, "PRX: " + px[0] + ":" + px[1] + "(" + px[2] + ")");
158 }
159 else
160 { 113 {
161 // Read application settings 114 // Read application settings
162 proxyHost = prefs.getString(getString(R.string.pref_proxyhost), null); 115 proxyHost = prefs.getString(getString(R.string.pref_proxyhost), null);
163 proxyPort = prefs.getString(getString(R.string.pref_proxyport), null); 116 proxyPort = prefs.getString(getString(R.string.pref_proxyport), null);
164 proxyUser = prefs.getString(getString(R.string.pref_proxyuser), null); 117 proxyUser = prefs.getString(getString(R.string.pref_proxyuser), null);
165 proxyPass = prefs.getString(getString(R.string.pref_proxypass), null); 118 proxyPass = prefs.getString(getString(R.string.pref_proxypass), null);
166 } 119 }
167 120
168 // Check for root privileges and try to install transparent proxy 121 registerReceiver(this.proxyReceiver, new IntentFilter(ProxyService.BROADCAST _PROXY_FAILED));
169 if (RootTools.isAccessGiven()) 122 registerReceiver(this.commandBridge, new IntentFilter(ProxyService.COMMAND_B RIDGE_ACTION));
123
124 final InetAddress inetAddress;
125 try
170 { 126 {
171 try 127 inetAddress = InetAddress.getByName(LOCALHOST);
172 {
173 initIptables();
174
175 final StringBuffer cmd = new StringBuffer();
176 final int uid = getPackageManager().getPackageInfo(getPackageName(), 0). applicationInfo.uid;
177 cmd.append(iptables);
178 cmd.append(IPTABLES_RETURN.replace("{{UID}}", String.valueOf(uid)));
179 final String rules = cmd.toString();
180 RootTools.sendShell(rules, DEFAULT_TIMEOUT);
181 transparent = true;
182 }
183 catch (final FileNotFoundException e)
184 {
185 // ignore - this is "normal" case
186 }
187 catch (final NameNotFoundException e)
188 {
189 Log.e(TAG, "Failed to initialize iptables", e);
190 }
191 catch (final IOException e)
192 {
193 Log.e(TAG, "Failed to initialize iptables", e);
194 }
195 catch (final RootToolsException e)
196 {
197 Log.e(TAG, "Failed to initialize iptables", e);
198 }
199 catch (final TimeoutException e)
200 {
201 Log.e(TAG, "Failed to initialize iptables", e);
202 }
203 } 128 }
204 129 catch (final UnknownHostException e)
205 if (!transparent)
206 { 130 {
207 // Try to set native proxy 131 sendBroadcast(new Intent(BROADCAST_PROXY_FAILED)
208 nativeProxyAutoConfigured = ProxySettings.setConnectionProxy(getApplicatio nContext(), LOCALHOST, port, ""); 132 .putExtra("msg", "Could not resolve 'localhost'"));
209 133 return;
210 if (NATIVE_PROXY_SUPPORTED)
211 {
212 registerReceiver(connectionReceiver, new IntentFilter(ConnectivityManage r.CONNECTIVITY_ACTION));
213 registerReceiver(connectionReceiver, new IntentFilter(Proxy.PROXY_CHANGE _ACTION));
214 }
215 } 134 }
216 135
217 // Save current native proxy situation. The service is always started on the first run so
218 // we will always have a correct value from the box
219 final SharedPreferences.Editor editor = prefs.edit();
220 editor.putBoolean(getString(R.string.pref_proxyautoconfigured), transparent || nativeProxyAutoConfigured);
221 editor.commit();
222
223 registerReceiver(proxyReceiver, new IntentFilter(ProxyService.BROADCAST_PROX Y_FAILED));
224 registerReceiver(filterReceiver, new IntentFilter(AdblockPlus.BROADCAST_FILT ERING_CHANGE));
225 registerReceiver(filterReceiver, new IntentFilter(AdblockPlus.BROADCAST_FILT ER_MATCHES));
226
227 // Start proxy 136 // Start proxy
228 if (proxy == null) 137 if (proxy == null)
229 { 138 {
230 // Select available port and bind to it, use previously selected port by d efault 139 // Select available port and bind to it, use previously selected port by d efault
231 portVariants[0] = prefs.getInt(getString(R.string.pref_lastport), -1);
232 ServerSocket listen = null; 140 ServerSocket listen = null;
233 String msg = null; 141 String msg = null;
234 for (final int p : portVariants) 142 for (final int p : PORT_VARIANTS)
235 { 143 {
236 if (p < 0) 144 final int toCheck = (p == -1) ? prefs.getInt(getString(R.string.pref_las tport), -1) : p;
237 continue; 145
238 try 146 if (toCheck >= 0)
239 { 147 {
240 // Fix for #232, bind proxy socket to loopback only 148 try
241 listen = new ServerSocket(p, 1024, InetAddress.getByName(LOCALHOST)); 149 {
242 port = p; 150 // Fix for #232, bind proxy socket to loopback only
243 break; 151 listen = new ServerSocket(toCheck, 1024, inetAddress);
244 } 152 this.port = listen.getLocalPort();
245 catch (final IOException e) 153 break;
246 { 154 }
247 Log.e(TAG, null, e); 155 catch (final IOException e)
248 msg = e.getMessage(); 156 {
157 Log.e(TAG, null, e);
158 msg = e.getMessage();
159 }
249 } 160 }
250 } 161 }
162
251 if (listen == null) 163 if (listen == null)
252 { 164 {
253 sendBroadcast(new Intent(BROADCAST_PROXY_FAILED).putExtra("msg", msg)); 165 sendBroadcast(new Intent(BROADCAST_PROXY_FAILED).putExtra("msg", msg));
254 return; 166 return;
255 } 167 }
256 168
169 this.proxyConfigurator = ProxyConfigurators.registerProxy(this, inetAddres s, this.port);
170
171 if (this.proxyConfigurator == null)
172 {
173 sendBroadcast(new Intent(BROADCAST_PROXY_FAILED)
174 .putExtra("msg", "Failed to register proxy"));
175 return;
176 }
177
257 // Save selected port 178 // Save selected port
179 final SharedPreferences.Editor editor = prefs.edit();
180 editor.putBoolean(getString(R.string.pref_proxyautoconfigured), this.getPr oxyRegistrationType().isAutoConfigured());
258 editor.putInt(getString(R.string.pref_lastport), port); 181 editor.putInt(getString(R.string.pref_lastport), port);
259 editor.commit(); 182 editor.commit();
260 183
261 // Initialize proxy 184 // Initialize proxy
262 proxyConfiguration.put("handler", "main"); 185 proxyConfiguration.put("handler", "main");
263 proxyConfiguration.put("main.prefix", ""); 186 proxyConfiguration.put("main.prefix", "");
264 proxyConfiguration.put("main.class", "sunlabs.brazil.server.ChainHandler") ; 187 proxyConfiguration.put("main.class", "sunlabs.brazil.server.ChainHandler") ;
265 if (transparent) 188 switch (this.getProxyRegistrationType().getProxyType())
266 { 189 {
190 case HTTP:
267 proxyConfiguration.put("main.handlers", "urlmodifier adblock"); 191 proxyConfiguration.put("main.handlers", "urlmodifier adblock");
268 proxyConfiguration.put("urlmodifier.class", "org.adblockplus.brazil.Tran sparentProxyHandler"); 192 proxyConfiguration.put("urlmodifier.class", "org.adblockplus.brazil.Tran sparentProxyHandler");
269 } 193 break;
270 else 194 case HTTPS:
271 {
272 proxyConfiguration.put("main.handlers", "https adblock"); 195 proxyConfiguration.put("main.handlers", "https adblock");
273 proxyConfiguration.put("https.class", "org.adblockplus.brazil.SSLConnect ionHandler"); 196 proxyConfiguration.put("https.class", "org.adblockplus.brazil.SSLConnect ionHandler");
197 break;
198 default:
199 sendBroadcast(new Intent(BROADCAST_PROXY_FAILED)
200 .putExtra("msg", "Unsupported proxy server type: " + this.getProxyRe gistrationType().getProxyType()));
201 return;
274 } 202 }
275 proxyConfiguration.put("adblock.class", "org.adblockplus.brazil.RequestHan dler"); 203 proxyConfiguration.put("adblock.class", "org.adblockplus.brazil.RequestHan dler");
276 if (logRequests) 204 if (LOG_REQUESTS)
277 proxyConfiguration.put("adblock.proxylog", "yes"); 205 proxyConfiguration.put("adblock.proxylog", "yes");
278 206
279 configureUserProxy(proxyConfiguration, proxyHost, proxyPort, proxyExcl, pr oxyUser, proxyPass); 207 configureUserProxy(proxyConfiguration, proxyHost, proxyPort, proxyExcl, pr oxyUser, proxyPass);
280 208
281 proxy = new ProxyServer(); 209 proxy = new ProxyServer();
282 proxy.logLevel = Server.LOG_DIAGNOSTIC; 210 proxy.logLevel = Server.LOG_LOG;
283 proxy.setup(listen, proxyConfiguration.getProperty("handler"), proxyConfig uration); 211 proxy.setup(listen, proxyConfiguration.getProperty("handler"), proxyConfig uration);
284 proxy.start(); 212 proxy.start();
285 } 213 }
286 214
287 if (transparent)
288 {
289 // Redirect traffic via iptables
290 try
291 {
292 final StringBuffer cmd = new StringBuffer();
293 cmd.append(iptables);
294 cmd.append(IPTABLES_ADD_HTTP.replace("{{PORT}}", String.valueOf(port)));
295 final String rules = cmd.toString();
296 RootTools.sendShell(rules, DEFAULT_TIMEOUT);
297 }
298 catch (final FileNotFoundException e)
299 {
300 // ignore - this is "normal" case
301 }
302 catch (final IOException e)
303 {
304 Log.e(TAG, "Failed to initialize iptables", e);
305 }
306 catch (final RootToolsException e)
307 {
308 Log.e(TAG, "Failed to initialize iptables", e);
309 }
310 catch (final TimeoutException e)
311 {
312 Log.e(TAG, "Failed to initialize iptables", e);
313 }
314 }
315
316 prefs.registerOnSharedPreferenceChangeListener(this); 215 prefs.registerOnSharedPreferenceChangeListener(this);
317 216
318 // Lock service 217 // Lock service
319 hideIcon = prefs.getBoolean(getString(R.string.pref_hideicon), resources.get Boolean(R.bool.def_hideicon)); 218 hideIcon = prefs.getBoolean(getString(R.string.pref_hideicon), getResources( ).getBoolean(R.bool.def_hideicon));
320 startForeground(ONGOING_NOTIFICATION_ID, getNotification()); 219 startForeground(ONGOING_NOTIFICATION_ID, getNotification());
321 220
322 // If automatic setting of proxy was blocked, check if user has set it manua lly
323 final boolean manual = isManual();
324 if (manual && NATIVE_PROXY_SUPPORTED)
325 {
326 final ConnectivityManager connectivityManager = (ConnectivityManager) getS ystemService(Context.CONNECTIVITY_SERVICE);
327 updateNoTrafficCheck(connectivityManager);
328 }
329
330 sendStateChangedBroadcast(); 221 sendStateChangedBroadcast();
331 Log.i(TAG, "Service started"); 222 Log.i(TAG, "Service started");
332 } 223 }
333 224
334 @Override 225 @Override
335 public int onStartCommand(final Intent intent, final int flags, final int star tId) 226 public int onStartCommand(final Intent intent, final int flags, final int star tId)
336 { 227 {
337 return START_STICKY; 228 return START_STICKY;
338 } 229 }
339 230
340 @Override 231 @Override
341 public void onDestroy() 232 public void onDestroy()
342 { 233 {
343 super.onDestroy(); 234 super.onDestroy();
344 235
345 stopNoTrafficCheck(); 236 unregisterReceiver(this.proxyReceiver);
237 unregisterReceiver(this.commandBridge);
346 238
347 unregisterReceiver(filterReceiver); 239 if (this.proxyConfigurator != null)
348 unregisterReceiver(proxyReceiver);
349
350 // Stop IP redirecting
351 if (transparent)
352 { 240 {
353 new Thread() 241 this.proxyConfigurator.unregisterProxy();
354 { 242 this.proxyConfigurator.shutdown();
355 @Override
356 public void run()
357 {
358 try
359 {
360 RootTools.sendShell(iptables + " -t nat -F OUTPUT", DEFAULT_TIMEOUT) ;
361 }
362 catch (final Exception e)
363 {
364 Log.e(TAG, "Failed to clear iptables", e);
365 }
366 }
367 }.start();
368 }
369
370 if (!transparent && NATIVE_PROXY_SUPPORTED)
371 unregisterReceiver(connectionReceiver);
372
373 // Clear native proxy
374 if (nativeProxyAutoConfigured)
375 {
376 clearConnectionProxy();
377 } 243 }
378 244
379 sendBroadcast(new Intent(BROADCAST_STATE_CHANGED).putExtra("enabled", false) ); 245 sendBroadcast(new Intent(BROADCAST_STATE_CHANGED).putExtra("enabled", false) );
380 246
381 // Stop proxy server 247 // Stop proxy server
382 if (proxy != null) 248 if (proxy != null)
249 {
383 proxy.close(); 250 proxy.close();
251 proxy = null;
252 }
384 253
385 // Release service lock 254 // Release service lock
386 stopForeground(true); 255 stopForeground(true);
387 256
388 Log.i(TAG, "Service stopped"); 257 Log.i(TAG, "Service stopped");
389 } 258 }
390 259
391 /** 260 /**
392 * Restores system proxy settings via native call on Android 3.1+ devices
393 * using Java reflection.
394 */
395 private void clearConnectionProxy()
396 {
397 final String proxyHost = proxyConfiguration.getProperty("adblock.proxyHost") ;
398 final String proxyPort = proxyConfiguration.getProperty("adblock.proxyPort") ;
399 final String proxyExcl = proxyConfiguration.getProperty("adblock.proxyExcl") ;
400 int port = 0;
401 try
402 {
403 if (proxyHost != null)
404 port = Integer.valueOf(proxyPort);
405 }
406 catch (final NumberFormatException e)
407 {
408 Log.e(TAG, "Bad port setting", e);
409 }
410 ProxySettings.setConnectionProxy(getApplicationContext(), proxyHost, port, p roxyExcl);
411 }
412
413 /**
414 * Sets user proxy settings in proxy service properties. 261 * Sets user proxy settings in proxy service properties.
415 */ 262 */
416 private void configureUserProxy(final Properties config, final String proxyHos t, final String proxyPort, final String proxyExcl, final String proxyUser, final String proxyPass) 263 private void configureUserProxy(final Properties config, final String proxyHos t, final String proxyPort, final String proxyExcl,
264 final String proxyUser, final String proxyPass)
417 { 265 {
418 // Clean previous settings 266 // Clean previous settings
419 config.remove("adblock.proxyHost"); 267 config.remove("adblock.proxyHost");
420 config.remove("adblock.proxyPort"); 268 config.remove("adblock.proxyPort");
421 config.remove("adblock.auth"); 269 config.remove("adblock.auth");
422 config.remove("adblock.proxyExcl"); 270 config.remove("adblock.proxyExcl");
423 if (!transparent) 271 config.remove("https.proxyHost");
272 config.remove("https.proxyPort");
273 config.remove("https.auth");
274
275 final ProxyRegistrationType regType = this.getProxyRegistrationType();
276 if (regType == ProxyRegistrationType.NATIVE)
424 { 277 {
425 config.remove("https.proxyHost"); 278 passProxySettings(proxyHost, proxyPort, proxyExcl);
426 config.remove("https.proxyPort");
427 config.remove("https.auth");
428 } 279 }
429 280
430 if (nativeProxyAutoConfigured)
431 passProxySettings(proxyHost, proxyPort, proxyExcl);
432
433 // Check if there are any settings 281 // Check if there are any settings
434 if (proxyHost == null || "".equals(proxyHost)) 282 if (StringUtils.isEmpty(proxyHost))
283 {
435 return; 284 return;
285 }
436 286
437 // Check for dirty proxy settings - this indicated previous crash: 287 // Check for dirty proxy settings - this indicated previous crash:
438 // proxy points to ourselves 288 // proxy points to ourselves
439 // proxy port is null, 0 or not a number 289 // proxy port is null, 0 or not a number
440 // proxy is 127.0.0.1:8080 290 // proxy is 127.0.0.1:8080
441 if (proxyPort == null) 291 if (proxyPort == null)
292 {
442 return; 293 return;
443 int p = 0; 294 }
295
296 final int p;
444 try 297 try
445 { 298 {
446 p = Integer.valueOf(proxyPort); 299 p = Integer.valueOf(proxyPort);
447 } 300 }
448 catch (final NumberFormatException e) 301 catch (final NumberFormatException e)
449 { 302 {
450 return; 303 return;
451 } 304 }
452 if (p == 0 || isLocalHost(proxyHost) && (p == port || p == 8080)) 305
306 if (p == 0 || isLocalhost(proxyHost) && (p == port || p == 8080))
453 { 307 {
454 if (nativeProxyAutoConfigured) 308 if (regType == ProxyRegistrationType.NATIVE)
309 {
455 passProxySettings(null, null, null); 310 passProxySettings(null, null, null);
311 }
456 return; 312 return;
457 } 313 }
458 314
459 config.put("adblock.proxyHost", proxyHost); 315 config.put("adblock.proxyHost", proxyHost);
460 config.put("adblock.proxyPort", proxyPort); 316 config.put("adblock.proxyPort", proxyPort);
461 if (!transparent) 317 if (regType.getProxyType() == ProxyServerType.HTTPS)
462 { 318 {
463 config.put("https.proxyHost", proxyHost); 319 config.put("https.proxyHost", proxyHost);
464 config.put("https.proxyPort", proxyPort); 320 config.put("https.proxyPort", proxyPort);
465 } 321 }
466 322
467 // TODO Not implemented in our proxy but needed to restore settings 323 // TODO Not implemented in our proxy but needed to restore settings
468 if (proxyExcl != null) 324 if (proxyExcl != null)
325 {
469 config.put("adblock.proxyExcl", proxyExcl); 326 config.put("adblock.proxyExcl", proxyExcl);
327 }
470 328
471 if (proxyUser != null && !"".equals(proxyUser) && proxyPass != null && !"".e quals(proxyPass)) 329 if (StringUtils.isNotEmpty(proxyUser) && StringUtils.isNotEmpty(proxyPass))
472 { 330 {
473 // Base64 encode user:password 331 // Base64 encode user:password
474 final String proxyAuth = "Basic " + new String(Base64.encode(proxyUser + " :" + proxyPass)); 332 final String proxyAuth = "Basic " + new String(Base64.encode(proxyUser + " :" + proxyPass));
475 config.put("adblock.auth", proxyAuth); 333 config.put("adblock.auth", proxyAuth);
476 if (!transparent) 334 if (regType.getProxyType() == ProxyServerType.HTTPS)
335 {
477 config.put("https.auth", proxyAuth); 336 config.put("https.auth", proxyAuth);
337 }
478 } 338 }
479 } 339 }
480 340
341 /**
342 * Lean method to send a {@link BridgeCommand} without additional extras.
343 *
344 * @param context
345 * the context to use for sending the broadcast
346 * @param command
347 * the command
348 */
349 public static void sendBridgeCommand(final Context context, final BridgeComman d command)
350 {
351 context.sendBroadcast(
352 new Intent(COMMAND_BRIDGE_ACTION)
353 .putExtra("command", command.toString()));
354 }
355
356 /**
357 * @return {@code true} if the given host string resolves to {@code localhost}
358 */
359 public static boolean isLocalhost(final String host)
360 {
361 try
362 {
363 if (StringUtils.isEmpty(host))
364 {
365 return false;
366 }
367
368 if (host.equals("127.0.0.1") || host.equalsIgnoreCase("localhost"))
369 {
370 return true;
371 }
372
373 return InetAddress.getByName(host).isLoopbackAddress();
374 }
375 catch (final Exception e)
376 {
377 return false;
378 }
379 }
380
481 private void passProxySettings(final String proxyHost, final String proxyPort, final String proxyExcl) 381 private void passProxySettings(final String proxyHost, final String proxyPort, final String proxyExcl)
482 { 382 {
483 try 383 try
484 { 384 {
485 final CrashHandler handler = (CrashHandler) Thread.getDefaultUncaughtExcep tionHandler(); 385 final CrashHandler handler = (CrashHandler) Thread.getDefaultUncaughtExcep tionHandler();
486 handler.saveProxySettings(proxyHost, proxyPort, proxyExcl); 386 handler.saveProxySettings(proxyHost, proxyPort, proxyExcl);
487 } 387 }
488 catch (final ClassCastException e) 388 catch (final ClassCastException e)
489 { 389 {
490 // ignore - default handler in use 390 // ignore - default handler in use
491 } 391 }
492 } 392 }
493 393
494 @Override 394 @Override
495 public void onSharedPreferenceChanged(final SharedPreferences sharedPreference s, final String key) 395 public void onSharedPreferenceChanged(final SharedPreferences sharedPreference s, final String key)
496 { 396 {
497 if (!NATIVE_PROXY_SUPPORTED) 397 // TODO verify this
398 if (this.getProxyRegistrationType() != ProxyRegistrationType.NATIVE)
498 { 399 {
499 final String ketHost = getString(R.string.pref_proxyhost); 400 final String keyHost = getString(R.string.pref_proxyhost);
500 final String keyPort = getString(R.string.pref_proxyport); 401 final String keyPort = getString(R.string.pref_proxyport);
501 final String keyUser = getString(R.string.pref_proxyuser); 402 final String keyUser = getString(R.string.pref_proxyuser);
502 final String keyPass = getString(R.string.pref_proxypass); 403 final String keyPass = getString(R.string.pref_proxypass);
503 if (key.equals(ketHost) || key.equals(keyPort) || key.equals(keyUser) || k ey.equals(keyPass)) 404 if (key.equals(keyHost) || key.equals(keyPort) || key.equals(keyUser) || k ey.equals(keyPass))
504 { 405 {
505 final String proxyHost = sharedPreferences.getString(ketHost, null); 406 final String proxyHost = sharedPreferences.getString(keyHost, null);
506 final String proxyPort = sharedPreferences.getString(keyPort, null); 407 final String proxyPort = sharedPreferences.getString(keyPort, null);
507 final String proxyUser = sharedPreferences.getString(keyUser, null); 408 final String proxyUser = sharedPreferences.getString(keyUser, null);
508 final String proxyPass = sharedPreferences.getString(keyPass, null); 409 final String proxyPass = sharedPreferences.getString(keyPass, null);
509 if (proxy != null) 410 if (proxy != null)
510 { 411 {
511 configureUserProxy(proxyConfiguration, proxyHost, proxyPort, null, pro xyUser, proxyPass); 412 configureUserProxy(proxyConfiguration, proxyHost, proxyPort, null, pro xyUser, proxyPass);
512 proxy.restart(proxyConfiguration.getProperty("handler")); 413 proxy.restart(proxyConfiguration.getProperty("handler"));
513 } 414 }
514 } 415 }
515 } 416 }
516 } 417 }
517 418
518 public boolean isTransparent()
519 {
520 return transparent;
521 }
522
523 public boolean isNativeProxyAutoConfigured()
524 {
525 return nativeProxyAutoConfigured;
526 }
527
528 /**
529 * Checks if user has to set proxy settings manually
530 */
531 public boolean isManual()
532 {
533 return !transparent && !nativeProxyAutoConfigured;
534 }
535
536 /**
537 * Checks whether traffic check is pending
538 */
539 public boolean noTraffic()
540 {
541 return notrafficHandler != null;
542 }
543
544 /**
545 * Checks if specified host is local.
546 */
547 private static final boolean isLocalHost(final String host)
548 {
549 if (host == null)
550 return false;
551
552 try
553 {
554 if (host.equalsIgnoreCase("localhost"))
555 return true;
556
557 final String className = "android.net.NetworkUtils";
558 final Class<?> c = Class.forName(className);
559 /*
560 * InetAddress address = NetworkUtils.numericToInetAddress(host);
561 */
562 final Method method = c.getMethod("numericToInetAddress", String.class);
563 final InetAddress address = (InetAddress) method.invoke(null, host);
564
565 if (address.isLoopbackAddress())
566 return true;
567 }
568 catch (final Exception e)
569 {
570 Log.w(TAG, null, e);
571 }
572 return false;
573 }
574
575 /**
576 * Initializes iptables executable.
577 *
578 * @throws FileNotFoundException
579 * If iptables initialization failed due to provided reasons.
580 */
581 private void initIptables() throws IOException, RootToolsException, TimeoutExc eption, FileNotFoundException
582 {
583 if (!RootTools.isAccessGiven())
584 throw new FileNotFoundException("No root access");
585
586 final File ipt = getFileStreamPath("iptables");
587
588 if (!ipt.exists())
589 {
590 Log.e(TAG, "No iptables excutable found");
591 throw new FileNotFoundException("No iptables executable");
592 }
593
594 final String path = ipt.getAbsolutePath();
595
596 RootTools.sendShell("chmod 700 " + path, DEFAULT_TIMEOUT);
597
598 boolean compatible = false;
599 boolean version = false;
600
601 final String command = path + " --version\n" + path + " -L -t nat -n\n";
602
603 final List<String> result = RootTools.sendShell(command, DEFAULT_TIMEOUT);
604 for (final String line : result)
605 {
606 if (line.contains("OUTPUT"))
607 compatible = true;
608 if (line.contains("v1.4."))
609 version = true;
610 }
611
612 if (!compatible || !version)
613 {
614 Log.e(TAG, "Incompatible iptables excutable");
615 throw new FileNotFoundException("Incompatible iptables excutable");
616 }
617
618 iptables = path;
619 }
620
621 public List<String> getIptablesOutput()
622 {
623 if (iptables == null)
624 return null;
625
626 final String command = iptables + " -L -t nat -n\n";
627 try
628 {
629 return RootTools.sendShell(command, DEFAULT_TIMEOUT);
630 }
631 catch (final Exception e)
632 {
633 Log.e(TAG, "Failed to get iptables configuration", e);
634 return null;
635 }
636 }
637
638 /** 419 /**
639 * Raises or removes no traffic notification based on current link proxy 420 * @return the active proxy configuration's type or {@link ProxyRegistrationTy pe#UNKNOWN} if none is configured
640 * settings
641 */ 421 */
642 private void updateNoTrafficCheck(final ConnectivityManager connectivityManage r) 422 public ProxyRegistrationType getProxyRegistrationType()
643 { 423 {
644 try 424 return this.proxyConfigurator != null ? this.proxyConfigurator.getType() : P roxyRegistrationType.UNKNOWN;
645 {
646 final Object pp = ProxySettings.getActiveLinkProxy(connectivityManager);
647 final String[] userProxy = ProxySettings.getUserProxy(pp);
648 if (userProxy != null)
649 Log.i(TAG, "Proxy settings: " + userProxy[0] + ":" + userProxy[1] + "(" + userProxy[2] + ")");
650 updateNoTrafficCheck(userProxy);
651 }
652 catch (final Exception e)
653 {
654 // This should not happen
655 Log.e(TAG, null, e);
656 }
657 } 425 }
658 426
659 /** 427 /**
660 * Raises or removes no traffic notification based on the user proxy settings 428 * @return {@code true} if there is a valid proxy configurator and registratio n succeeded
661 */ 429 */
662 private void updateNoTrafficCheck(final String[] userProxy) 430 public boolean isRegistered()
663 { 431 {
664 final boolean ourProxy = userProxy != null && isLocalHost(userProxy[0]) && I nteger.valueOf(userProxy[1]) == port; 432 return this.proxyConfigurator != null && this.proxyConfigurator.isRegistered ();
665 if (ourProxy != proxyManualyConfigured)
666 {
667 proxyManualyConfigured = ourProxy;
668 sendStateChangedBroadcast();
669 }
670 if (ourProxy)
671 {
672 stopNoTrafficCheck();
673 }
674 else
675 {
676 // Initiate no traffic check
677 notrafficHandler = new Handler();
678 notrafficHandler.postDelayed(noTraffic, NO_TRAFFIC_TIMEOUT);
679 }
680 final NotificationManager notificationManager = (NotificationManager) getSys temService(NOTIFICATION_SERVICE);
681 notificationManager.notify(ONGOING_NOTIFICATION_ID, getNotification());
682 } 433 }
683 434
684 /** 435 /**
685 * Stops no traffic check and resets notification message. 436 * @return {@code true} if registration type is {@link ProxyRegistrationType#N ATIVE} and registration succeeded
686 */ 437 */
687 private void stopNoTrafficCheck() 438 public boolean isNativeProxyAutoConfigured()
688 { 439 {
689 if (notrafficHandler != null) 440 return this.getProxyRegistrationType() == ProxyRegistrationType.NATIVE && th is.isRegistered();
690 { 441 }
691 notrafficHandler.removeCallbacks(noTraffic); 442
692 sendStateChangedBroadcast(); 443 /**
693 final NotificationManager notificationManager = (NotificationManager) getS ystemService(NOTIFICATION_SERVICE); 444 * @return {@code true} if registration type is {@link ProxyRegistrationType#M ANUAL}
694 notificationManager.notify(ONGOING_NOTIFICATION_ID, getNotification()); 445 */
695 notificationManager.cancel(NOTRAFFIC_NOTIFICATION_ID); 446 public boolean isManual()
Felix Dahlke 2014/08/19 16:14:46 IMO it'd be neat to have isNative() and isIptables
René Jeschke 2014/08/19 16:33:24 At least 'isIptables()'. Done.
696 } 447 {
697 notrafficHandler = null; 448 return this.getProxyRegistrationType() == ProxyRegistrationType.MANUAL;
698 } 449 }
699 450
700 @SuppressLint("NewApi") 451 @SuppressLint("NewApi")
701 private Notification getNotification() 452 private Notification getNotification()
702 { 453 {
703 final boolean filtering = AdblockPlus.getApplication().isFilteringEnabled(); 454 final boolean filtering = AdblockPlus.getApplication().isFilteringEnabled();
704 455
705 int msgId = R.string.notif_waiting; 456 final int msgId;
706 if (nativeProxyAutoConfigured || proxyManualyConfigured) 457 switch(this.getProxyRegistrationType())
458 {
459 case MANUAL:
460 if (this.isRegistered())
461 {
462 msgId = filtering ? R.string.notif_wifi : R.string.notif_wifi_nofilterin g;
463 }
464 else
465 {
466 msgId = filtering ? R.string.notif_waiting : R.string.notif_wifi_nofilte ring;
467 }
468 break;
469 case NATIVE:
707 msgId = filtering ? R.string.notif_wifi : R.string.notif_wifi_nofiltering; 470 msgId = filtering ? R.string.notif_wifi : R.string.notif_wifi_nofiltering;
708 if (transparent) 471 break;
472 case IPTABLES:
473 case CYANOGENMOD:
Felix Dahlke 2014/08/19 16:14:46 Do we currently filter non-wifi traffic on Cyanoge
René Jeschke 2014/08/19 16:33:24 Of course we are filtering all connection traffic
Felix Dahlke 2014/08/19 16:47:05 How about adding this to ProxyConfigurationType? S
René Jeschke 2014/08/23 11:33:31 As discussed in RL, we leave it like it is.
709 msgId = R.string.notif_all; 474 msgId = R.string.notif_all;
475 break;
476 default:
477 msgId = R.string.notif_waiting;
478 break;
479 }
710 480
711 final NotificationCompat.Builder builder = new NotificationCompat.Builder(th is); 481 final NotificationCompat.Builder builder = new NotificationCompat.Builder(th is);
712 if (hideIcon && msgId != R.string.notif_waiting) 482 if (hideIcon && msgId != R.string.notif_waiting)
713 { 483 {
714 builder.setWhen(POSITION_RIGHT); 484 builder.setWhen(POSITION_RIGHT);
715 builder.setSmallIcon(R.drawable.transparent); 485 builder.setSmallIcon(R.drawable.transparent);
716 // builder.setContent(new RemoteViews(getPackageName(), R.layout.notif_hid den));
717 } 486 }
718 else 487 else
719 { 488 {
720 builder.setWhen(0); 489 builder.setWhen(0);
721 builder.setSmallIcon(R.drawable.ic_stat_blocking); 490 builder.setSmallIcon(R.drawable.ic_stat_blocking);
722 } 491 }
723 final PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new I ntent(this, Preferences.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent. FLAG_ACTIVITY_NEW_TASK), 0); 492 final PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
493 new Intent(this, Preferences.class).addFlags(Intent.FLAG_ACTIVITY_CLEAR_ TOP | Intent.FLAG_ACTIVITY_NEW_TASK), 0);
494
724 builder.setContentIntent(contentIntent); 495 builder.setContentIntent(contentIntent);
725 builder.setContentTitle(getText(R.string.app_name)); 496 builder.setContentTitle(getText(R.string.app_name));
726 builder.setContentText(getString(msgId, port)); 497 builder.setContentText(getString(msgId, port));
727 builder.setOngoing(true); 498 builder.setOngoing(true);
728 499
729 final Notification notification = builder.getNotification(); 500 return builder.getNotification();
730 return notification;
731 } 501 }
732 502
733 public void setEmptyIcon(final boolean hide) 503 public void setEmptyIcon(final boolean hide)
734 { 504 {
735 hideIcon = hide; 505 hideIcon = hide;
736 final NotificationManager notificationManager = (NotificationManager) getSys temService(NOTIFICATION_SERVICE); 506 final NotificationManager notificationManager = (NotificationManager) getSys temService(NOTIFICATION_SERVICE);
737 notificationManager.notify(ONGOING_NOTIFICATION_ID, getNotification()); 507 notificationManager.notify(ONGOING_NOTIFICATION_ID, getNotification());
738 } 508 }
739 509
740 public void sendStateChangedBroadcast() 510 public void sendStateChangedBroadcast()
741 { 511 {
742 Log.i(TAG, "Broadcasting " + BROADCAST_STATE_CHANGED);
743 final boolean manual = isManual(); 512 final boolean manual = isManual();
744 final Intent stateIntent = new Intent(BROADCAST_STATE_CHANGED).putExtra("ena bled", true).putExtra("port", port).putExtra("manual", manual); 513 final Intent stateIntent = new Intent(BROADCAST_STATE_CHANGED)
514 .putExtra("enabled", true)
515 .putExtra("port", port)
516 .putExtra("manual", manual);
517
745 if (manual) 518 if (manual)
746 stateIntent.putExtra("configured", proxyManualyConfigured); 519 {
520 stateIntent.putExtra("configured", this.isRegistered());
521 }
522
747 sendBroadcast(stateIntent); 523 sendBroadcast(stateIntent);
748 } 524 }
749 525
750 private final IBinder binder = new LocalBinder(); 526 private final IBinder binder = new LocalBinder();
751 527
752 public final class LocalBinder extends Binder 528 public final class LocalBinder extends Binder
753 { 529 {
754 public ProxyService getService() 530 public ProxyService getService()
755 { 531 {
756 return ProxyService.this; 532 return ProxyService.this;
757 } 533 }
758 } 534 }
759 535
760 @Override 536 @Override
761 public IBinder onBind(final Intent intent) 537 public IBinder onBind(final Intent intent)
762 { 538 {
763 return binder; 539 return binder;
764 } 540 }
765 541
766 /** 542 /**
767 * Executed if no traffic is detected after a period of time. Notifies user
768 * about possible configuration problems.
769 */
770 private final Runnable noTraffic = new Runnable()
771 {
772 @Override
773 public void run()
774 {
775 // It's weird but notrafficHandler.removeCallbacks(noTraffic) does not rem ove this callback
776 if (notrafficHandler == null)
777 return;
778 // Show warning notification
779 final NotificationCompat.Builder builder = new NotificationCompat.Builder( ProxyService.this);
780 builder.setSmallIcon(R.drawable.ic_stat_warning);
781 builder.setWhen(System.currentTimeMillis());
782 builder.setAutoCancel(true);
783 final Intent intent = new Intent(ProxyService.this, ConfigurationActivity. class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
784 intent.putExtra("port", port);
785 final PendingIntent contentIntent = PendingIntent.getActivity(ProxyService .this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
786 builder.setContentIntent(contentIntent);
787 builder.setContentTitle(getText(R.string.app_name));
788 builder.setContentText(getText(R.string.notif_notraffic));
789 final NotificationManager notificationManager = (NotificationManager) getS ystemService(NOTIFICATION_SERVICE);
790 notificationManager.notify(NOTRAFFIC_NOTIFICATION_ID, builder.getNotificat ion());
791 }
792 };
793
794 /**
795 * Stops no traffic check if traffic is detected by proxy service.
796 */
797 private final BroadcastReceiver filterReceiver = new BroadcastReceiver()
798 {
799 @Override
800 public void onReceive(final Context context, final Intent intent)
801 {
802 if (intent.getAction().equals(AdblockPlus.BROADCAST_FILTERING_CHANGE))
803 {
804 // It's rather a hack but things are happening simultaneously and we
805 // receive this broadcast despite the fact we have unsubscribed from
806 // it and notification is not removed because it is changed to new one
807 // during removal.
808 if (!isNativeProxyAutoConfigured())
809 {
810 final NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
811 notificationManager.notify(ONGOING_NOTIFICATION_ID, getNotification()) ;
812 }
813 }
814 if (intent.getAction().equals(AdblockPlus.BROADCAST_FILTER_MATCHES))
815 {
816 proxyManualyConfigured = true;
817 stopNoTrafficCheck();
818 }
819 }
820 };
821
822 /**
823 * Stops service if proxy fails. 543 * Stops service if proxy fails.
824 */ 544 */
825 private final BroadcastReceiver proxyReceiver = new BroadcastReceiver() 545 private final BroadcastReceiver proxyReceiver = new BroadcastReceiver()
826 { 546 {
827 @Override 547 @Override
828 public void onReceive(final Context context, final Intent intent) 548 public void onReceive(final Context context, final Intent intent)
829 { 549 {
830 if (intent.getAction().equals(ProxyService.BROADCAST_PROXY_FAILED)) 550 if (intent.getAction().equals(ProxyService.BROADCAST_PROXY_FAILED))
831 { 551 {
832 stopSelf(); 552 stopSelf();
833 } 553 }
834 } 554 }
835 }; 555 };
836 556
837 /** 557 /**
838 * Monitors system network connection settings changes and updates proxy 558 * <p>
839 * settings accordingly. 559 * A BR for simple message passing from various ProxyConfigurators.
560 * </p>
561 * <p>
562 * The purpose of this BroadcastReceiver is to allow other components to send notifications to the service and to be prepared for upcoming service
563 * refactorings.
Felix Dahlke 2014/08/19 16:14:46 As discussed on IRC before, I don't understand yet
564 * </p>
840 */ 565 */
841 private final BroadcastReceiver connectionReceiver = new BroadcastReceiver() 566 private final BroadcastReceiver commandBridge = new BroadcastReceiver()
842 { 567 {
843 @Override 568 @Override
844 public void onReceive(final Context ctx, final Intent intent) 569 public void onReceive(final Context context, final Intent intent)
845 { 570 {
846 final String action = intent.getAction(); 571 if (intent != null)
847 Log.i(TAG, "Action: " + action);
848 // Connectivity change
849 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action))
850 { 572 {
851 final ConnectivityManager connectivityManager = (ConnectivityManager) ge tSystemService(Context.CONNECTIVITY_SERVICE); 573 switch (BridgeCommand.fromString(intent.getStringExtra("command")))
852 // TODO Should we use ConnectivityManagerCompat.getNetworkInfoFromBroadc ast() instead?
853 final NetworkInfo info = connectivityManager.getActiveNetworkInfo();
854 if (info == null)
855 return;
856 final String typeName = info.getTypeName();
857 final String subtypeName = info.getSubtypeName();
858 final boolean available = info.isAvailable();
859
860 Log.i(TAG, "Network Type: " + typeName + ", subtype: " + subtypeName + " , available: " + available);
861 if (info.getType() == ConnectivityManager.TYPE_WIFI)
862 { 574 {
863 if (nativeProxyAutoConfigured) 575 case STATE_CHANGED:
864 { 576 final NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
865 ProxySettings.setConnectionProxy(getApplicationContext(), LOCALHOST, port, ""); 577 notificationManager.notify(ONGOING_NOTIFICATION_ID, getNotification()) ;
866 } 578 ProxyService.this.sendStateChangedBroadcast();
867 else 579 break;
868 { 580 default:
869 updateNoTrafficCheck(connectivityManager); 581 // ignore
870 } 582 break;
871 }
872 }
873 // Proxy change
874 else if (Proxy.PROXY_CHANGE_ACTION.equals(action))
875 {
876 final Object pp = intent.getParcelableExtra("proxy");
877 try
878 {
879 final String[] userProxy = ProxySettings.getUserProxy(pp);
880 if (nativeProxyAutoConfigured)
881 {
882 if (userProxy != null && Integer.valueOf(userProxy[1]) != port)
883 {
884 Log.i(TAG, "User has set new proxy: " + userProxy[0] + ":" + userP roxy[1] + "(" + userProxy[2] + ")");
885 if (proxy != null)
886 {
887 configureUserProxy(proxyConfiguration, userProxy[0], userProxy[1 ], userProxy[2], null, null);
888 proxy.restart(proxyConfiguration.getProperty("handler"));
889 }
890 }
891 }
892 else
893 {
894 Log.i(TAG, "User has set proxy: " + userProxy[0] + ":" + userProxy[1 ] + "(" + userProxy[2] + ")");
895 updateNoTrafficCheck(userProxy);
896 }
897 }
898 catch (final Exception e)
899 {
900 // This should not happen
901 Log.e(TAG, null, e);
902 } 583 }
903 } 584 }
904 } 585 }
905 }; 586 };
906 587
907 final class ProxyServer extends Server 588 final class ProxyServer extends Server
908 { 589 {
909 @Override 590 @Override
910 public void close() 591 public void close()
911 { 592 {
(...skipping 13 matching lines...) Expand all
925 @Override 606 @Override
926 public void log(final int level, final Object obj, final String message) 607 public void log(final int level, final Object obj, final String message)
927 { 608 {
928 if (level <= logLevel) 609 if (level <= logLevel)
929 { 610 {
930 Log.println(7 - level, obj != null ? obj.toString() : TAG, message); 611 Log.println(7 - level, obj != null ? obj.toString() : TAG, message);
931 } 612 }
932 } 613 }
933 } 614 }
934 } 615 }
OLDNEW

Powered by Google App Engine
This is Rietveld