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 java.io.ByteArrayOutputStream; 24 import java.io.IOException; 25 import java.io.InputStream; 26 import java.net.HttpURLConnection; 27 import java.net.URL; 28 import java.util.Properties; 29 import java.util.Random; 30 import java.util.concurrent.TimeUnit; 31 32 /** 33 * A class for downloading GPS XTRA data. 34 * 35 * {@hide} 36 */ 37 public class GpsXtraDownloader { 38 39 private static final String TAG = "GpsXtraDownloader"; 40 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 41 private static final long MAXIMUM_CONTENT_LENGTH_BYTES = 1000000; // 1MB. 42 private static final String DEFAULT_USER_AGENT = "Android"; 43 private static final int CONNECTION_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(30); 44 private static final int READ_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(60); 45 46 private final String[] mXtraServers; 47 // to load balance our server requests 48 private int mNextServerIndex; 49 private final String mUserAgent; 50 51 GpsXtraDownloader(Properties properties) { 52 // read XTRA servers from the Properties object 53 int count = 0; 54 String server1 = properties.getProperty("XTRA_SERVER_1"); 55 String server2 = properties.getProperty("XTRA_SERVER_2"); 56 String server3 = properties.getProperty("XTRA_SERVER_3"); 57 if (server1 != null) count++; 58 if (server2 != null) count++; 59 if (server3 != null) count++; 60 61 // Set User Agent from properties, if possible. 62 String agent = properties.getProperty("XTRA_USER_AGENT"); 63 if (TextUtils.isEmpty(agent)) { 64 mUserAgent = DEFAULT_USER_AGENT; 65 } else { 66 mUserAgent = agent; 67 } 68 69 if (count == 0) { 70 Log.e(TAG, "No XTRA servers were specified in the GPS configuration"); 71 mXtraServers = null; 72 } else { 73 mXtraServers = new String[count]; 74 count = 0; 75 if (server1 != null) mXtraServers[count++] = server1; 76 if (server2 != null) mXtraServers[count++] = server2; 77 if (server3 != null) mXtraServers[count++] = server3; 78 79 // randomize first server 80 Random random = new Random(); 81 mNextServerIndex = random.nextInt(count); 82 } 83 } 84 85 byte[] downloadXtraData() { 86 byte[] result = null; 87 int startIndex = mNextServerIndex; 88 89 if (mXtraServers == null) { 90 return null; 91 } 92 93 // load balance our requests among the available servers 94 while (result == null) { 95 final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_GPS); 96 try { 97 result = doDownload(mXtraServers[mNextServerIndex]); 98 } finally { 99 TrafficStats.setThreadStatsTag(oldTag); 100 } 101 102 // increment mNextServerIndex and wrap around if necessary 103 mNextServerIndex++; 104 if (mNextServerIndex == mXtraServers.length) { 105 mNextServerIndex = 0; 106 } 107 // break if we have tried all the servers 108 if (mNextServerIndex == startIndex) break; 109 } 110 111 return result; 112 } 113 114 protected byte[] doDownload(String url) { 115 if (DEBUG) Log.d(TAG, "Downloading XTRA data from " + url); 116 117 HttpURLConnection connection = null; 118 try { 119 connection = (HttpURLConnection) (new URL(url)).openConnection(); 120 connection.setRequestProperty( 121 "Accept", 122 "*/*, application/vnd.wap.mms-message, application/vnd.wap.sic"); 123 connection.setRequestProperty( 124 "x-wap-profile", 125 "http://www.openmobilealliance.org/tech/profiles/UAPROF/ccppschema-20021212#"); 126 connection.setConnectTimeout(CONNECTION_TIMEOUT_MS); 127 connection.setReadTimeout(READ_TIMEOUT_MS); 128 129 connection.connect(); 130 int statusCode = connection.getResponseCode(); 131 if (statusCode != HttpURLConnection.HTTP_OK) { 132 if (DEBUG) Log.d(TAG, "HTTP error downloading gps XTRA: " + statusCode); 133 return null; 134 } 135 136 try (InputStream in = connection.getInputStream()) { 137 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 138 byte[] buffer = new byte[1024]; 139 int count; 140 while ((count = in.read(buffer)) != -1) { 141 bytes.write(buffer, 0, count); 142 if (bytes.size() > MAXIMUM_CONTENT_LENGTH_BYTES) { 143 if (DEBUG) Log.d(TAG, "XTRA file too large"); 144 return null; 145 } 146 } 147 return bytes.toByteArray(); 148 } 149 } catch (IOException ioe) { 150 if (DEBUG) Log.d(TAG, "Error downloading gps XTRA: ", ioe); 151 } finally { 152 if (connection != null) { 153 connection.disconnect(); 154 } 155 } 156 return null; 157 } 158 159 } 160 161