blob: b4985509047c9e415c93579cfe72063096995ce5 [file] [log] [blame]
Irfan Sheriffb8c0e002013-02-20 14:19:54 -08001/*
2 * Copyright (C) 2013 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 com.android.server.wifi;
18
19import android.content.BroadcastReceiver;
20import android.content.Context;
21import android.content.Intent;
22import android.content.IntentFilter;
23import android.net.NetworkInfo;
24import static android.net.NetworkInfo.DetailedState.CONNECTED;
25import android.net.TrafficStats;
26import android.net.wifi.WifiManager;
Irfan Sheriff302b06d2013-02-22 12:35:31 -080027import android.os.Messenger;
28import android.os.RemoteException;
29import android.util.Log;
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080030import android.os.Handler;
31import android.os.Message;
32
33import java.io.FileDescriptor;
34import java.io.PrintWriter;
Irfan Sheriffc808a192013-03-05 09:46:36 -080035import java.util.ArrayList;
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080036import java.util.List;
37import java.util.concurrent.atomic.AtomicBoolean;
38
39import com.android.internal.util.AsyncChannel;
40
41/* Polls for traffic stats and notifies the clients */
42final class WifiTrafficPoller {
43 /**
44 * Interval in milliseconds between polling for traffic
45 * statistics
46 */
47 private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
48
Irfan Sheriffc808a192013-03-05 09:46:36 -080049 private static final int ENABLE_TRAFFIC_STATS_POLL = 1;
50 private static final int TRAFFIC_STATS_POLL = 2;
51 private static final int ADD_CLIENT = 3;
52 private static final int REMOVE_CLIENT = 4;
53
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080054 private boolean mEnableTrafficStatsPoll = false;
55 private int mTrafficStatsPollToken = 0;
56 private long mTxPkts;
57 private long mRxPkts;
58 /* Tracks last reported data activity */
59 private int mDataActivity;
60
Irfan Sheriffc808a192013-03-05 09:46:36 -080061 private final List<Messenger> mClients = new ArrayList<Messenger>();
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080062 // err on the side of updating at boot since screen on broadcast may be missed
63 // the first time
64 private AtomicBoolean mScreenOn = new AtomicBoolean(true);
65 private final TrafficHandler mTrafficHandler;
66 private NetworkInfo mNetworkInfo;
67 private final String mInterface;
68
Irfan Sheriffc808a192013-03-05 09:46:36 -080069 WifiTrafficPoller(Context context, String iface) {
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080070 mInterface = iface;
71 mTrafficHandler = new TrafficHandler();
72
73 IntentFilter filter = new IntentFilter();
74 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
75 filter.addAction(Intent.ACTION_SCREEN_OFF);
76 filter.addAction(Intent.ACTION_SCREEN_ON);
77
78 context.registerReceiver(
79 new BroadcastReceiver() {
80 @Override
81 public void onReceive(Context context, Intent intent) {
82 if (intent.getAction().equals(
83 WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
84 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
85 WifiManager.EXTRA_NETWORK_INFO);
86 } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
87 mScreenOn.set(false);
88 } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
89 mScreenOn.set(true);
90 }
91 evaluateTrafficStatsPolling();
92 }
93 }, filter);
94 }
95
Irfan Sheriffc808a192013-03-05 09:46:36 -080096 void addClient(Messenger client) {
97 Message.obtain(mTrafficHandler, ADD_CLIENT, client).sendToTarget();
98 }
99
100 void removeClient(Messenger client) {
101 Message.obtain(mTrafficHandler, REMOVE_CLIENT, client).sendToTarget();
102 }
103
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800104
105 private class TrafficHandler extends Handler {
106 public void handleMessage(Message msg) {
107 switch (msg.what) {
Irfan Sheriffc808a192013-03-05 09:46:36 -0800108 case ENABLE_TRAFFIC_STATS_POLL:
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800109 mEnableTrafficStatsPoll = (msg.arg1 == 1);
110 mTrafficStatsPollToken++;
111 if (mEnableTrafficStatsPoll) {
112 notifyOnDataActivity();
Irfan Sheriffc808a192013-03-05 09:46:36 -0800113 sendMessageDelayed(Message.obtain(this, TRAFFIC_STATS_POLL,
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800114 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
115 }
116 break;
Irfan Sheriffc808a192013-03-05 09:46:36 -0800117 case TRAFFIC_STATS_POLL:
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800118 if (msg.arg1 == mTrafficStatsPollToken) {
119 notifyOnDataActivity();
Irfan Sheriffc808a192013-03-05 09:46:36 -0800120 sendMessageDelayed(Message.obtain(this, TRAFFIC_STATS_POLL,
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800121 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
122 }
123 break;
Irfan Sheriffc808a192013-03-05 09:46:36 -0800124 case ADD_CLIENT:
125 mClients.add((Messenger) msg.obj);
126 break;
127 case REMOVE_CLIENT:
128 mClients.remove(msg.obj);
129 break;
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800130 }
131
132 }
133 }
134
135 private void evaluateTrafficStatsPolling() {
136 Message msg;
137 if (mNetworkInfo == null) return;
138 if (mNetworkInfo.getDetailedState() == CONNECTED && mScreenOn.get()) {
139 msg = Message.obtain(mTrafficHandler,
Irfan Sheriffc808a192013-03-05 09:46:36 -0800140 ENABLE_TRAFFIC_STATS_POLL, 1, 0);
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800141 } else {
142 msg = Message.obtain(mTrafficHandler,
Irfan Sheriffc808a192013-03-05 09:46:36 -0800143 ENABLE_TRAFFIC_STATS_POLL, 0, 0);
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800144 }
145 msg.sendToTarget();
146 }
147
148 private void notifyOnDataActivity() {
149 long sent, received;
150 long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
151 int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
152
153 mTxPkts = TrafficStats.getTxPackets(mInterface);
154 mRxPkts = TrafficStats.getRxPackets(mInterface);
155
156 if (preTxPkts > 0 || preRxPkts > 0) {
157 sent = mTxPkts - preTxPkts;
158 received = mRxPkts - preRxPkts;
159 if (sent > 0) {
160 dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
161 }
162 if (received > 0) {
163 dataActivity |= WifiManager.DATA_ACTIVITY_IN;
164 }
165
166 if (dataActivity != mDataActivity && mScreenOn.get()) {
167 mDataActivity = dataActivity;
Irfan Sheriff302b06d2013-02-22 12:35:31 -0800168 for (Messenger client : mClients) {
169 Message msg = Message.obtain();
170 msg.what = WifiManager.DATA_ACTIVITY_NOTIFICATION;
171 msg.arg1 = mDataActivity;
172 try {
173 client.send(msg);
174 } catch (RemoteException e) {
175 // Failed to reach, skip
176 // Client removal is handled in WifiService
177 }
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800178 }
179 }
180 }
181 }
182
183 void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
184 pw.println("mEnableTrafficStatsPoll " + mEnableTrafficStatsPoll);
185 pw.println("mTrafficStatsPollToken " + mTrafficStatsPollToken);
186 pw.println("mTxPkts " + mTxPkts);
187 pw.println("mRxPkts " + mRxPkts);
188 pw.println("mDataActivity " + mDataActivity);
189 }
190
191}