1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.location; 18 19 import android.net.TrafficStats; 20 import android.text.TextUtils; 21 import android.util.Log; 22 23 import com.android.internal.util.TrafficStatsConstants; 24 25 import java.io.ByteArrayOutputStream; 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.net.HttpURLConnection; 29 import java.net.URL; 30 import java.util.Properties; 31 import java.util.Random; 32 import java.util.concurrent.TimeUnit; 33 34 /** 35 * A class for downloading GPS PSDS data. 36 * 37 * {@hide} 38 */ 39 public class GpsPsdsDownloader { 40 41 private static final String TAG = "GpsPsdsDownloader"; 42 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 43 private static final long MAXIMUM_CONTENT_LENGTH_BYTES = 1000000; // 1MB. 44 private static final String DEFAULT_USER_AGENT = "Android"; 45 private static final int CONNECTION_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30); 46 private static final int READ_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(60); 47 48 private final String[] mPsdsServers; 49 // to load balance our server requests 50 private int mNextServerIndex; 51 private final String mUserAgent; 52 GpsPsdsDownloader(Properties properties)53 GpsPsdsDownloader(Properties properties) { 54 // read PSDS servers from the Properties object 55 int count = 0; 56 String server1 = properties.getProperty("XTRA_SERVER_1"); 57 String server2 = properties.getProperty("XTRA_SERVER_2"); 58 String server3 = properties.getProperty("XTRA_SERVER_3"); 59 if (server1 != null) count++; 60 if (server2 != null) count++; 61 if (server3 != null) count++; 62 63 // Set User Agent from properties, if possible. 64 String agent = properties.getProperty("XTRA_USER_AGENT"); 65 if (TextUtils.isEmpty(agent)) { 66 mUserAgent = DEFAULT_USER_AGENT; 67 } else { 68 mUserAgent = agent; 69 } 70 71 if (count == 0) { 72 Log.e(TAG, "No PSDS servers were specified in the GPS configuration"); 73 mPsdsServers = null; 74 } else { 75 mPsdsServers = new String[count]; 76 count = 0; 77 if (server1 != null) mPsdsServers[count++] = server1; 78 if (server2 != null) mPsdsServers[count++] = server2; 79 if (server3 != null) mPsdsServers[count++] = server3; 80 81 // randomize first server 82 Random random = new Random(); 83 mNextServerIndex = random.nextInt(count); 84 } 85 } 86 downloadPsdsData()87 byte[] downloadPsdsData() { 88 byte[] result = null; 89 int startIndex = mNextServerIndex; 90 91 if (mPsdsServers == null) { 92 return null; 93 } 94 95 // load balance our requests among the available servers 96 while (result == null) { 97 final int oldTag = TrafficStats.getAndSetThreadStatsTag( 98 TrafficStatsConstants.TAG_SYSTEM_GPS); 99 try { 100 result = doDownload(mPsdsServers[mNextServerIndex]); 101 } finally { 102 TrafficStats.setThreadStatsTag(oldTag); 103 } 104 105 // increment mNextServerIndex and wrap around if necessary 106 mNextServerIndex++; 107 if (mNextServerIndex == mPsdsServers.length) { 108 mNextServerIndex = 0; 109 } 110 // break if we have tried all the servers 111 if (mNextServerIndex == startIndex) break; 112 } 113 114 return result; 115 } 116 doDownload(String url)117 protected byte[] doDownload(String url) { 118 if (DEBUG) Log.d(TAG, "Downloading PSDS data from " + url); 119 120 HttpURLConnection connection = null; 121 try { 122 connection = (HttpURLConnection) (new URL(url)).openConnection(); 123 connection.setRequestProperty( 124 "Accept", 125 "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic"); 126 connection.setRequestProperty( 127 "x-wap-profile", 128 "http://www.openmobilealliance.org/tech/profiles/UAPROF/ccppschema-20021212#"); 129 connection.setConnectTimeout(CONNECTION_TIMEOUT_MS); 130 connection.setReadTimeout(READ_TIMEOUT_MS); 131 132 connection.connect(); 133 int statusCode = connection.getResponseCode(); 134 if (statusCode != HttpURLConnection.HTTP_OK) { 135 if (DEBUG) Log.d(TAG, "HTTP error downloading gps PSDS: " + statusCode); 136 return null; 137 } 138 139 try (InputStream in = connection.getInputStream()) { 140 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 141 byte[] buffer = new byte[1024]; 142 int count; 143 while ((count = in.read(buffer)) != -1) { 144 bytes.write(buffer, 0, count); 145 if (bytes.size() > MAXIMUM_CONTENT_LENGTH_BYTES) { 146 if (DEBUG) Log.d(TAG, "PSDS file too large"); 147 return null; 148 } 149 } 150 return bytes.toByteArray(); 151 } 152 } catch (IOException ioe) { 153 if (DEBUG) Log.d(TAG, "Error downloading gps PSDS: ", ioe); 154 } finally { 155 if (connection != null) { 156 connection.disconnect(); 157 } 158 } 159 return null; 160 } 161 162 } 163 164