19ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk/** 29ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * Copyright (c) 2013, The Android Open Source Project 39ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * 49ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); 59ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * you may not use this file except in compliance with the License. 69ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * You may obtain a copy of the License at 79ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * 89ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * http://www.apache.org/licenses/LICENSE-2.0 99ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * 109ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * Unless required by applicable law or agreed to in writing, software 119ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * distributed under the License is distributed on an "AS IS" BASIS, 129ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * See the License for the specific language governing permissions and 149ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk * limitations under the License. 159ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk */ 16602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkpackage com.android.server.connectivity; 17602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 184010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hironoimport android.annotation.WorkerThread; 19602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.app.AlarmManager; 20602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.app.PendingIntent; 21602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.content.BroadcastReceiver; 229ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monkimport android.content.ComponentName; 23602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.content.ContentResolver; 24602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.content.Context; 25602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.content.Intent; 26602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.content.IntentFilter; 279ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monkimport android.content.ServiceConnection; 28207900c23b26d0df9ab28c709db4a1007d7d7904Jason Monkimport android.net.ProxyInfo; 29619a511d4f5b5cc74b9a8ab853db386489e02e6fJeff Sharkeyimport android.net.TrafficStats; 3083520b95124e0fcaaf3154a7a267f6be0205bc74Jason Monkimport android.net.Uri; 31decd295b1371238c97c170226c6145948492eda1Jason Monkimport android.os.Handler; 327d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensenimport android.os.HandlerThread; 339ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monkimport android.os.IBinder; 34602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.os.RemoteException; 35602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.os.ServiceManager; 36602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.os.SystemClock; 37602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.os.SystemProperties; 38602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.provider.Settings; 39602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport android.util.Log; 40602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 419ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monkimport com.android.internal.annotations.GuardedBy; 426f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monkimport com.android.net.IProxyCallback; 436f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monkimport com.android.net.IProxyPortListener; 44602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport com.android.net.IProxyService; 45602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 469ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monkimport libcore.io.Streams; 47602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 487d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensenimport java.io.ByteArrayOutputStream; 49602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.io.IOException; 50602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.URL; 51602b232a06ede86999aa362a12eb28cbc782dc1dJason Monkimport java.net.URLConnection; 52602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 53602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk/** 54602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk * @hide 55602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk */ 569ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monkpublic class PacManager { 57da205a749fadb3a87357d9bd607f094c7717764aJason Monk public static final String PAC_PACKAGE = "com.android.pacprocessor"; 58da205a749fadb3a87357d9bd607f094c7717764aJason Monk public static final String PAC_SERVICE = "com.android.pacprocessor.PacService"; 59da205a749fadb3a87357d9bd607f094c7717764aJason Monk public static final String PAC_SERVICE_NAME = "com.android.net.IProxyService"; 60602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 61da205a749fadb3a87357d9bd607f094c7717764aJason Monk public static final String PROXY_PACKAGE = "com.android.proxyhandler"; 62da205a749fadb3a87357d9bd607f094c7717764aJason Monk public static final String PROXY_SERVICE = "com.android.proxyhandler.ProxyService"; 63602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 649ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk private static final String TAG = "PacManager"; 65602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 66602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private static final String ACTION_PAC_REFRESH = "android.net.proxy.PAC_REFRESH"; 67602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 68602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private static final String DEFAULT_DELAYS = "8 32 120 14400 43200"; 69602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private static final int DELAY_1 = 0; 70602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private static final int DELAY_4 = 3; 71602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private static final int DELAY_LONG = 4; 727d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen private static final long MAX_PAC_SIZE = 20 * 1000 * 1000; 73602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 74602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk /** Keep these values up-to-date with ProxyService.java */ 75602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public static final String KEY_PROXY = "keyProxy"; 76602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private String mCurrentPac; 779ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk @GuardedBy("mProxyLock") 784010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono private volatile Uri mPacUrl = Uri.EMPTY; 79602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 80602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private AlarmManager mAlarmManager; 819ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk @GuardedBy("mProxyLock") 82602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private IProxyService mProxyService; 83602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private PendingIntent mPacRefreshIntent; 849ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk private ServiceConnection mConnection; 85da205a749fadb3a87357d9bd607f094c7717764aJason Monk private ServiceConnection mProxyConnection; 86602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private Context mContext; 87602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 88602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private int mCurrentDelay; 896f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk private int mLastPort; 90602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 914010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono private volatile boolean mHasSentBroadcast; 924010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono private volatile boolean mHasDownloaded; 93d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk 94decd295b1371238c97c170226c6145948492eda1Jason Monk private Handler mConnectivityHandler; 95decd295b1371238c97c170226c6145948492eda1Jason Monk private int mProxyMessage; 96decd295b1371238c97c170226c6145948492eda1Jason Monk 979ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk /** 984010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono * Used for locking when setting mProxyService and all references to mCurrentPac. 999ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk */ 1009ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk private final Object mProxyLock = new Object(); 1019ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk 1024010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono /** 1034010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono * Runnable to download PAC script. 1044010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono * The behavior relies on the assamption it always run on mNetThread to guarantee that the 1054010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono * latest data fetched from mPacUrl is stored in mProxyService. 1064010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono */ 1079ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk private Runnable mPacDownloader = new Runnable() { 1089ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk @Override 1094010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono @WorkerThread 1109ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk public void run() { 1119ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk String file; 1124010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono final Uri pacUrl = mPacUrl; 1134010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono if (Uri.EMPTY.equals(pacUrl)) return; 1144010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PAC); 1154010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono try { 1164010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono file = get(pacUrl); 1174010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono } catch (IOException ioe) { 1184010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono file = null; 1194010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono Log.w(TAG, "Failed to load PAC file: " + ioe); 1204010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono } finally { 1214010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono TrafficStats.setThreadStatsTag(oldTag); 1229ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 1239ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk if (file != null) { 1249ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk synchronized (mProxyLock) { 1259ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk if (!file.equals(mCurrentPac)) { 1269ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk setCurrentProxyScript(file); 1279ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 1289ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 129d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk mHasDownloaded = true; 130d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk sendProxyIfNeeded(); 1319ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk longSchedule(); 1329ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } else { 1339ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk reschedule(); 1349ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 1359ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 1369ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk }; 1379ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk 1387d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen private final HandlerThread mNetThread = new HandlerThread("android.pacmanager", 1397d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen android.os.Process.THREAD_PRIORITY_DEFAULT); 1407d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen private final Handler mNetThreadHandler; 1417d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen 142602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk class PacRefreshIntentReceiver extends BroadcastReceiver { 143602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk public void onReceive(Context context, Intent intent) { 1447d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen mNetThreadHandler.post(mPacDownloader); 145602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 146602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 147602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 148decd295b1371238c97c170226c6145948492eda1Jason Monk public PacManager(Context context, Handler handler, int proxyMessage) { 149602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk mContext = context; 1506f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk mLastPort = -1; 1517d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen mNetThread.start(); 1527d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen mNetThreadHandler = new Handler(mNetThread.getLooper()); 153602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 154602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk mPacRefreshIntent = PendingIntent.getBroadcast( 155602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk context, 0, new Intent(ACTION_PAC_REFRESH), 0); 156602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk context.registerReceiver(new PacRefreshIntentReceiver(), 157602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk new IntentFilter(ACTION_PAC_REFRESH)); 158decd295b1371238c97c170226c6145948492eda1Jason Monk mConnectivityHandler = handler; 159decd295b1371238c97c170226c6145948492eda1Jason Monk mProxyMessage = proxyMessage; 160602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 161602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 162602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private AlarmManager getAlarmManager() { 163602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (mAlarmManager == null) { 164602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 165602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 166602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return mAlarmManager; 167602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 168602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 1696f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk /** 1706f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk * Updates the PAC Manager with current Proxy information. This is called by 1716f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk * the ConnectivityService directly before a broadcast takes place to allow 1726f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk * the PacManager to indicate that the broadcast should not be sent and the 1736f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk * PacManager will trigger a new broadcast when it is ready. 1746f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk * 1756f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk * @param proxy Proxy information that is about to be broadcast. 1766f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk * @return Returns true when the broadcast should not be sent 1776f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk */ 178207900c23b26d0df9ab28c709db4a1007d7d7904Jason Monk public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) { 17983520b95124e0fcaaf3154a7a267f6be0205bc74Jason Monk if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) { 18090760c8fa36574d6cc9224046758317ca6f640bfJason Monk if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) { 181decd295b1371238c97c170226c6145948492eda1Jason Monk // Allow to send broadcast, nothing to do. 182decd295b1371238c97c170226c6145948492eda1Jason Monk return false; 183decd295b1371238c97c170226c6145948492eda1Jason Monk } 1844010fe49486338f9aa31aba238c60d1837ce1e74Daichi Hirono mPacUrl = proxy.getPacFileUrl(); 1859ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mCurrentDelay = DELAY_1; 186d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk mHasSentBroadcast = false; 187d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk mHasDownloaded = false; 1889ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk getAlarmManager().cancel(mPacRefreshIntent); 1899ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk bind(); 1906f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk return true; 191602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } else { 1929ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk getAlarmManager().cancel(mPacRefreshIntent); 1939ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk synchronized (mProxyLock) { 194f6b46cb8b108cc8feee8ae68b979271fd6f72bf5Jason Monk mPacUrl = Uri.EMPTY; 1959ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mCurrentPac = null; 1969ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk if (mProxyService != null) { 1979ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk try { 1989ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mProxyService.stopPacSystem(); 1999ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } catch (RemoteException e) { 2009ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk Log.w(TAG, "Failed to stop PAC service", e); 2019ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } finally { 2029ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk unbind(); 2039ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 2049ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 205602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 2066f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk return false; 207602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 208602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 209602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 210602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk /** 211602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk * Does a post and reports back the status code. 212602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk * 213602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk * @throws IOException 214602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk */ 21583520b95124e0fcaaf3154a7a267f6be0205bc74Jason Monk private static String get(Uri pacUri) throws IOException { 21683520b95124e0fcaaf3154a7a267f6be0205bc74Jason Monk URL url = new URL(pacUri.toString()); 217602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk URLConnection urlConnection = url.openConnection(java.net.Proxy.NO_PROXY); 2187d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen long contentLength = -1; 2197d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen try { 2207d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen contentLength = Long.parseLong(urlConnection.getHeaderField("Content-Length")); 2217d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen } catch (NumberFormatException e) { 2227d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen // Ignore 2237d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen } 2247d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen if (contentLength > MAX_PAC_SIZE) { 2257d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen throw new IOException("PAC too big: " + contentLength + " bytes"); 2267d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen } 2277d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 2287d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen byte[] buffer = new byte[1024]; 2297d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen int count; 2307d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen while ((count = urlConnection.getInputStream().read(buffer)) != -1) { 2317d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen bytes.write(buffer, 0, count); 2327d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen if (bytes.size() > MAX_PAC_SIZE) { 2337d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen throw new IOException("PAC too big"); 2347d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen } 2357d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen } 2367d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen return bytes.toString(); 237602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 238602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 239602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private int getNextDelay(int currentDelay) { 240602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (++currentDelay > DELAY_4) { 241602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return DELAY_4; 242602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 243602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return currentDelay; 244602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 245602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 246602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private void longSchedule() { 247602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk mCurrentDelay = DELAY_1; 248602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk setDownloadIn(DELAY_LONG); 249602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 250602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 251602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private void reschedule() { 252602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk mCurrentDelay = getNextDelay(mCurrentDelay); 253602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk setDownloadIn(mCurrentDelay); 254602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 255602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 256602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private String getPacChangeDelay() { 257602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk final ContentResolver cr = mContext.getContentResolver(); 258602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 259602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk /** Check system properties for the default value then use secure settings value, if any. */ 260602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String defaultDelay = SystemProperties.get( 261602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk "conn." + Settings.Global.PAC_CHANGE_DELAY, 262602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk DEFAULT_DELAYS); 263602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String val = Settings.Global.getString(cr, Settings.Global.PAC_CHANGE_DELAY); 264602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return (val == null) ? defaultDelay : val; 265602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 266602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 267602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private long getDownloadDelay(int delayIndex) { 268602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk String[] list = getPacChangeDelay().split(" "); 269602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk if (delayIndex < list.length) { 270602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return Long.parseLong(list[delayIndex]); 271602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 272602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return 0; 273602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 274602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 275602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private void setDownloadIn(int delayIndex) { 276602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk long delay = getDownloadDelay(delayIndex); 277602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk long timeTillTrigger = 1000 * delay + SystemClock.elapsedRealtime(); 278602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk getAlarmManager().set(AlarmManager.ELAPSED_REALTIME, timeTillTrigger, mPacRefreshIntent); 279602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 280602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk 281602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk private boolean setCurrentProxyScript(String script) { 282a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville if (mProxyService == null) { 283a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville Log.e(TAG, "setCurrentProxyScript: no proxy service"); 284a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville return false; 285a48ad8bd858d6ffe77838a282dbf71e01967957cWink Saville } 286602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk try { 2879ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mProxyService.setPacFile(script); 288602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk mCurrentPac = script; 289602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } catch (RemoteException e) { 290602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk Log.e(TAG, "Unable to set PAC file", e); 291602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 292602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk return true; 293602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk } 2949ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk 2959ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk private void bind() { 2969ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk if (mContext == null) { 2979ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk Log.e(TAG, "No context for binding"); 2989ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk return; 2999ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 3009ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk Intent intent = new Intent(); 301da205a749fadb3a87357d9bd607f094c7717764aJason Monk intent.setClassName(PAC_PACKAGE, PAC_SERVICE); 302bc018d89c27cdd93d1c0222a6e27965455974b9eJason Monk if ((mProxyConnection != null) && (mConnection != null)) { 3034bf1d218576fa5721bab589cd5945dbe49f0d117Jason Monk // Already bound no need to bind again, just download the new file. 304baae57ab24db7d3b0bf7f84c05954173f1ee15fePaul Jensen mNetThreadHandler.post(mPacDownloader); 3056f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk return; 3066f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 3079ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mConnection = new ServiceConnection() { 3089ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk @Override 3099ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk public void onServiceDisconnected(ComponentName component) { 3109ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk synchronized (mProxyLock) { 3119ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mProxyService = null; 3129ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 3139ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 3149ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk 3159ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk @Override 3169ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk public void onServiceConnected(ComponentName component, IBinder binder) { 3179ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk synchronized (mProxyLock) { 3189ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk try { 319da205a749fadb3a87357d9bd607f094c7717764aJason Monk Log.d(TAG, "Adding service " + PAC_SERVICE_NAME + " " 3209ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk + binder.getInterfaceDescriptor()); 3219ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } catch (RemoteException e1) { 3229ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk Log.e(TAG, "Remote Exception", e1); 3239ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 324da205a749fadb3a87357d9bd607f094c7717764aJason Monk ServiceManager.addService(PAC_SERVICE_NAME, binder); 3259ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mProxyService = IProxyService.Stub.asInterface(binder); 3269ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk if (mProxyService == null) { 3279ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk Log.e(TAG, "No proxy service"); 3289ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } else { 3299ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk try { 3309ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mProxyService.startPacSystem(); 3319ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } catch (RemoteException e) { 3329ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk Log.e(TAG, "Unable to reach ProxyService - PAC will not be started", e); 3339ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 3347d2198b586bcfbf96fb627021a0eb85d32829cc0Paul Jensen mNetThreadHandler.post(mPacDownloader); 3359ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 3369ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 3379ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 3389ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk }; 3399ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk mContext.bindService(intent, mConnection, 3409ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE); 341da205a749fadb3a87357d9bd607f094c7717764aJason Monk 342da205a749fadb3a87357d9bd607f094c7717764aJason Monk intent = new Intent(); 343da205a749fadb3a87357d9bd607f094c7717764aJason Monk intent.setClassName(PROXY_PACKAGE, PROXY_SERVICE); 344da205a749fadb3a87357d9bd607f094c7717764aJason Monk mProxyConnection = new ServiceConnection() { 345da205a749fadb3a87357d9bd607f094c7717764aJason Monk @Override 346da205a749fadb3a87357d9bd607f094c7717764aJason Monk public void onServiceDisconnected(ComponentName component) { 347da205a749fadb3a87357d9bd607f094c7717764aJason Monk } 348da205a749fadb3a87357d9bd607f094c7717764aJason Monk 349da205a749fadb3a87357d9bd607f094c7717764aJason Monk @Override 350da205a749fadb3a87357d9bd607f094c7717764aJason Monk public void onServiceConnected(ComponentName component, IBinder binder) { 3516f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk IProxyCallback callbackService = IProxyCallback.Stub.asInterface(binder); 3526f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk if (callbackService != null) { 3536f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk try { 3546f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk callbackService.getProxyPort(new IProxyPortListener.Stub() { 3556f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk @Override 3566f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk public void setProxyPort(int port) throws RemoteException { 357d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk if (mLastPort != -1) { 358d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk // Always need to send if port changed 359d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk mHasSentBroadcast = false; 360d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk } 3616f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk mLastPort = port; 3626f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk if (port != -1) { 3636f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk Log.d(TAG, "Local proxy is bound on " + port); 364d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk sendProxyIfNeeded(); 3656f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } else { 3666f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk Log.e(TAG, "Received invalid port from Local Proxy," 3676f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk + " PAC will not be operational"); 3686f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 3696f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 3706f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk }); 3716f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } catch (RemoteException e) { 3726f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk e.printStackTrace(); 3736f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 3746f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 375da205a749fadb3a87357d9bd607f094c7717764aJason Monk } 376da205a749fadb3a87357d9bd607f094c7717764aJason Monk }; 377da205a749fadb3a87357d9bd607f094c7717764aJason Monk mContext.bindService(intent, mProxyConnection, 378da205a749fadb3a87357d9bd607f094c7717764aJason Monk Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND | Context.BIND_NOT_VISIBLE); 3799ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 3809ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk 3819ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk private void unbind() { 382bc018d89c27cdd93d1c0222a6e27965455974b9eJason Monk if (mConnection != null) { 383bc018d89c27cdd93d1c0222a6e27965455974b9eJason Monk mContext.unbindService(mConnection); 384bc018d89c27cdd93d1c0222a6e27965455974b9eJason Monk mConnection = null; 385bc018d89c27cdd93d1c0222a6e27965455974b9eJason Monk } 386bc018d89c27cdd93d1c0222a6e27965455974b9eJason Monk if (mProxyConnection != null) { 387bc018d89c27cdd93d1c0222a6e27965455974b9eJason Monk mContext.unbindService(mProxyConnection); 388bc018d89c27cdd93d1c0222a6e27965455974b9eJason Monk mProxyConnection = null; 389bc018d89c27cdd93d1c0222a6e27965455974b9eJason Monk } 390bc018d89c27cdd93d1c0222a6e27965455974b9eJason Monk mProxyService = null; 391d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk mLastPort = -1; 3926f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk } 3936f8a68f49a7e8cf86104e721a1e8be7568b5f730Jason Monk 394207900c23b26d0df9ab28c709db4a1007d7d7904Jason Monk private void sendPacBroadcast(ProxyInfo proxy) { 395decd295b1371238c97c170226c6145948492eda1Jason Monk mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy)); 3969ced3cd9d6ea414523051ec872fffc68f5fdbf08Jason Monk } 397d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk 398d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk private synchronized void sendProxyIfNeeded() { 399d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk if (!mHasDownloaded || (mLastPort == -1)) { 400d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk return; 401d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk } 402d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk if (!mHasSentBroadcast) { 403207900c23b26d0df9ab28c709db4a1007d7d7904Jason Monk sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort)); 404d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk mHasSentBroadcast = true; 405d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk } 406d443479a45279f8f52daf4034698f2ab3c3e62f1Jason Monk } 407602b232a06ede86999aa362a12eb28cbc782dc1dJason Monk} 408