/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.support.v4.net; import android.os.Build; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketException; /** * Helper for accessing features in TrafficStats introduced after API level 14 * in a backwards compatible fashion. */ public final class TrafficStatsCompat { interface TrafficStatsCompatImpl { void clearThreadStatsTag(); int getThreadStatsTag(); void incrementOperationCount(int operationCount); void incrementOperationCount(int tag, int operationCount); void setThreadStatsTag(int tag); void tagSocket(Socket socket) throws SocketException; void untagSocket(Socket socket) throws SocketException; void tagDatagramSocket(DatagramSocket socket) throws SocketException; void untagDatagramSocket(DatagramSocket socket) throws SocketException; } static class BaseTrafficStatsCompatImpl implements TrafficStatsCompatImpl { private static class SocketTags { public int statsTag = -1; } private ThreadLocal mThreadSocketTags = new ThreadLocal() { @Override protected SocketTags initialValue() { return new SocketTags(); } }; @Override public void clearThreadStatsTag() { mThreadSocketTags.get().statsTag = -1; } @Override public int getThreadStatsTag() { return mThreadSocketTags.get().statsTag; } @Override public void incrementOperationCount(int operationCount) { } @Override public void incrementOperationCount(int tag, int operationCount) { } @Override public void setThreadStatsTag(int tag) { mThreadSocketTags.get().statsTag = tag; } @Override public void tagSocket(Socket socket) { } @Override public void untagSocket(Socket socket) { } @Override public void tagDatagramSocket(DatagramSocket socket) { } @Override public void untagDatagramSocket(DatagramSocket socket) { } } static class IcsTrafficStatsCompatImpl implements TrafficStatsCompatImpl { @Override public void clearThreadStatsTag() { TrafficStatsCompatIcs.clearThreadStatsTag(); } @Override public int getThreadStatsTag() { return TrafficStatsCompatIcs.getThreadStatsTag(); } @Override public void incrementOperationCount(int operationCount) { TrafficStatsCompatIcs.incrementOperationCount(operationCount); } @Override public void incrementOperationCount(int tag, int operationCount) { TrafficStatsCompatIcs.incrementOperationCount(tag, operationCount); } @Override public void setThreadStatsTag(int tag) { TrafficStatsCompatIcs.setThreadStatsTag(tag); } @Override public void tagSocket(Socket socket) throws SocketException { TrafficStatsCompatIcs.tagSocket(socket); } @Override public void untagSocket(Socket socket) throws SocketException { TrafficStatsCompatIcs.untagSocket(socket); } @Override public void tagDatagramSocket(DatagramSocket socket) throws SocketException { TrafficStatsCompatIcs.tagDatagramSocket(socket); } @Override public void untagDatagramSocket(DatagramSocket socket) throws SocketException { TrafficStatsCompatIcs.untagDatagramSocket(socket); } } static class Api24TrafficStatsCompatImpl extends IcsTrafficStatsCompatImpl { @Override public void tagDatagramSocket(DatagramSocket socket) throws SocketException { TrafficStatsCompatApi24.tagDatagramSocket(socket); } @Override public void untagDatagramSocket(DatagramSocket socket) throws SocketException { TrafficStatsCompatApi24.untagDatagramSocket(socket); } } private static final TrafficStatsCompatImpl IMPL; static { if ("N".equals(Build.VERSION.CODENAME)) { IMPL = new Api24TrafficStatsCompatImpl(); } else if (Build.VERSION.SDK_INT >= 14) { IMPL = new IcsTrafficStatsCompatImpl(); } else { IMPL = new BaseTrafficStatsCompatImpl(); } } /** * Clear active tag used when accounting {@link Socket} traffic originating * from the current thread. */ public static void clearThreadStatsTag() { IMPL.clearThreadStatsTag(); } /** * Get the active tag used when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. * {@link #tagSocket(Socket)}. */ public static int getThreadStatsTag() { return IMPL.getThreadStatsTag(); } /** * Increment count of network operations performed under the accounting tag * currently active on the calling thread. This can be used to derive * bytes-per-operation. * * @param operationCount Number of operations to increment count by. */ public static void incrementOperationCount(int operationCount) { IMPL.incrementOperationCount(operationCount); } /** * Increment count of network operations performed under the given * accounting tag. This can be used to derive bytes-per-operation. * * @param tag Accounting tag used in {@link #setThreadStatsTag(int)}. * @param operationCount Number of operations to increment count by. */ public static void incrementOperationCount(int tag, int operationCount) { IMPL.incrementOperationCount(tag, operationCount); } /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. *

* Changes only take effect during subsequent calls to * {@link #tagSocket(Socket)}. *

* Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and * used internally by system services like DownloadManager when performing * traffic on behalf of an application. */ public static void setThreadStatsTag(int tag) { IMPL.setThreadStatsTag(tag); } /** * Tag the given {@link Socket} with any statistics parameters active for * the current thread. Subsequent calls always replace any existing * parameters. When finished, call {@link #untagSocket(Socket)} to remove * statistics parameters. * * @see #setThreadStatsTag(int) */ public static void tagSocket(Socket socket) throws SocketException { IMPL.tagSocket(socket); } /** * Remove any statistics parameters from the given {@link Socket}. */ public static void untagSocket(Socket socket) throws SocketException { IMPL.untagSocket(socket); } /** * Tag the given {@link DatagramSocket} with any statistics parameters * active for the current thread. Subsequent calls always replace any * existing parameters. When finished, call * {@link #untagDatagramSocket(DatagramSocket)} to remove statistics * parameters. * * @see #setThreadStatsTag(int) */ public static void tagDatagramSocket(DatagramSocket socket) throws SocketException { IMPL.tagDatagramSocket(socket); } /** * Remove any statistics parameters from the given {@link DatagramSocket}. */ public static void untagDatagramSocket(DatagramSocket socket) throws SocketException { IMPL.untagDatagramSocket(socket); } private TrafficStatsCompat() {} }