1/* 2 * Copyright (C) 2012 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 17package android.support.v4.net; 18 19import android.os.Build; 20 21import java.net.DatagramSocket; 22import java.net.Socket; 23import java.net.SocketException; 24 25/** 26 * Helper for accessing features in TrafficStats introduced after API level 14 27 * in a backwards compatible fashion. 28 */ 29public final class TrafficStatsCompat { 30 31 interface TrafficStatsCompatImpl { 32 void clearThreadStatsTag(); 33 int getThreadStatsTag(); 34 void incrementOperationCount(int operationCount); 35 void incrementOperationCount(int tag, int operationCount); 36 void setThreadStatsTag(int tag); 37 void tagSocket(Socket socket) throws SocketException; 38 void untagSocket(Socket socket) throws SocketException; 39 void tagDatagramSocket(DatagramSocket socket) throws SocketException; 40 void untagDatagramSocket(DatagramSocket socket) throws SocketException; 41 } 42 43 static class BaseTrafficStatsCompatImpl implements TrafficStatsCompatImpl { 44 private static class SocketTags { 45 public int statsTag = -1; 46 47 SocketTags() { 48 } 49 } 50 51 private ThreadLocal<SocketTags> mThreadSocketTags = new ThreadLocal<SocketTags>() { 52 @Override 53 protected SocketTags initialValue() { 54 return new SocketTags(); 55 } 56 }; 57 58 @Override 59 public void clearThreadStatsTag() { 60 mThreadSocketTags.get().statsTag = -1; 61 } 62 63 @Override 64 public int getThreadStatsTag() { 65 return mThreadSocketTags.get().statsTag; 66 } 67 68 @Override 69 public void incrementOperationCount(int operationCount) { 70 } 71 72 @Override 73 public void incrementOperationCount(int tag, int operationCount) { 74 } 75 76 @Override 77 public void setThreadStatsTag(int tag) { 78 mThreadSocketTags.get().statsTag = tag; 79 } 80 81 @Override 82 public void tagSocket(Socket socket) { 83 } 84 85 @Override 86 public void untagSocket(Socket socket) { 87 } 88 89 @Override 90 public void tagDatagramSocket(DatagramSocket socket) { 91 } 92 93 @Override 94 public void untagDatagramSocket(DatagramSocket socket) { 95 } 96 } 97 98 static class IcsTrafficStatsCompatImpl implements TrafficStatsCompatImpl { 99 @Override 100 public void clearThreadStatsTag() { 101 TrafficStatsCompatIcs.clearThreadStatsTag(); 102 } 103 104 @Override 105 public int getThreadStatsTag() { 106 return TrafficStatsCompatIcs.getThreadStatsTag(); 107 } 108 109 @Override 110 public void incrementOperationCount(int operationCount) { 111 TrafficStatsCompatIcs.incrementOperationCount(operationCount); 112 } 113 114 @Override 115 public void incrementOperationCount(int tag, int operationCount) { 116 TrafficStatsCompatIcs.incrementOperationCount(tag, operationCount); 117 } 118 119 @Override 120 public void setThreadStatsTag(int tag) { 121 TrafficStatsCompatIcs.setThreadStatsTag(tag); 122 } 123 124 @Override 125 public void tagSocket(Socket socket) throws SocketException { 126 TrafficStatsCompatIcs.tagSocket(socket); 127 } 128 129 @Override 130 public void untagSocket(Socket socket) throws SocketException { 131 TrafficStatsCompatIcs.untagSocket(socket); 132 } 133 134 @Override 135 public void tagDatagramSocket(DatagramSocket socket) throws SocketException { 136 TrafficStatsCompatIcs.tagDatagramSocket(socket); 137 } 138 139 @Override 140 public void untagDatagramSocket(DatagramSocket socket) throws SocketException { 141 TrafficStatsCompatIcs.untagDatagramSocket(socket); 142 } 143 } 144 145 static class Api24TrafficStatsCompatImpl extends IcsTrafficStatsCompatImpl { 146 @Override 147 public void tagDatagramSocket(DatagramSocket socket) throws SocketException { 148 TrafficStatsCompatApi24.tagDatagramSocket(socket); 149 } 150 151 @Override 152 public void untagDatagramSocket(DatagramSocket socket) throws SocketException { 153 TrafficStatsCompatApi24.untagDatagramSocket(socket); 154 } 155 } 156 157 private static final TrafficStatsCompatImpl IMPL; 158 159 static { 160 if ("N".equals(Build.VERSION.CODENAME)) { 161 IMPL = new Api24TrafficStatsCompatImpl(); 162 } else if (Build.VERSION.SDK_INT >= 14) { 163 IMPL = new IcsTrafficStatsCompatImpl(); 164 } else { 165 IMPL = new BaseTrafficStatsCompatImpl(); 166 } 167 } 168 169 /** 170 * Clear active tag used when accounting {@link Socket} traffic originating 171 * from the current thread. 172 */ 173 public static void clearThreadStatsTag() { 174 IMPL.clearThreadStatsTag(); 175 } 176 177 /** 178 * Get the active tag used when accounting {@link Socket} traffic originating 179 * from the current thread. Only one active tag per thread is supported. 180 * {@link #tagSocket(Socket)}. 181 */ 182 public static int getThreadStatsTag() { 183 return IMPL.getThreadStatsTag(); 184 } 185 186 /** 187 * Increment count of network operations performed under the accounting tag 188 * currently active on the calling thread. This can be used to derive 189 * bytes-per-operation. 190 * 191 * @param operationCount Number of operations to increment count by. 192 */ 193 public static void incrementOperationCount(int operationCount) { 194 IMPL.incrementOperationCount(operationCount); 195 } 196 197 /** 198 * Increment count of network operations performed under the given 199 * accounting tag. This can be used to derive bytes-per-operation. 200 * 201 * @param tag Accounting tag used in {@link #setThreadStatsTag(int)}. 202 * @param operationCount Number of operations to increment count by. 203 */ 204 public static void incrementOperationCount(int tag, int operationCount) { 205 IMPL.incrementOperationCount(tag, operationCount); 206 } 207 208 /** 209 * Set active tag to use when accounting {@link Socket} traffic originating 210 * from the current thread. Only one active tag per thread is supported. 211 * <p> 212 * Changes only take effect during subsequent calls to 213 * {@link #tagSocket(Socket)}. 214 * <p> 215 * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and 216 * used internally by system services like DownloadManager when performing 217 * traffic on behalf of an application. 218 */ 219 public static void setThreadStatsTag(int tag) { 220 IMPL.setThreadStatsTag(tag); 221 } 222 223 /** 224 * Tag the given {@link Socket} with any statistics parameters active for 225 * the current thread. Subsequent calls always replace any existing 226 * parameters. When finished, call {@link #untagSocket(Socket)} to remove 227 * statistics parameters. 228 * 229 * @see #setThreadStatsTag(int) 230 */ 231 public static void tagSocket(Socket socket) throws SocketException { 232 IMPL.tagSocket(socket); 233 } 234 235 /** 236 * Remove any statistics parameters from the given {@link Socket}. 237 */ 238 public static void untagSocket(Socket socket) throws SocketException { 239 IMPL.untagSocket(socket); 240 } 241 242 /** 243 * Tag the given {@link DatagramSocket} with any statistics parameters 244 * active for the current thread. Subsequent calls always replace any 245 * existing parameters. When finished, call 246 * {@link #untagDatagramSocket(DatagramSocket)} to remove statistics 247 * parameters. 248 * 249 * @see #setThreadStatsTag(int) 250 */ 251 public static void tagDatagramSocket(DatagramSocket socket) throws SocketException { 252 IMPL.tagDatagramSocket(socket); 253 } 254 255 /** 256 * Remove any statistics parameters from the given {@link DatagramSocket}. 257 */ 258 public static void untagDatagramSocket(DatagramSocket socket) throws SocketException { 259 IMPL.untagDatagramSocket(socket); 260 } 261 262 private TrafficStatsCompat() {} 263} 264