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