blob: 5678086594aeed62d703300381b1256dcc897fb7 [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;
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080029import android.os.Handler;
30import android.os.Message;
31
32import java.io.FileDescriptor;
33import java.io.PrintWriter;
Irfan Sheriffc808a192013-03-05 09:46:36 -080034import java.util.ArrayList;
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080035import java.util.List;
36import java.util.concurrent.atomic.AtomicBoolean;
37
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080038/* Polls for traffic stats and notifies the clients */
39final class WifiTrafficPoller {
40 /**
41 * Interval in milliseconds between polling for traffic
42 * statistics
43 */
44 private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000;
45
Irfan Sheriffc808a192013-03-05 09:46:36 -080046 private static final int ENABLE_TRAFFIC_STATS_POLL = 1;
47 private static final int TRAFFIC_STATS_POLL = 2;
48 private static final int ADD_CLIENT = 3;
49 private static final int REMOVE_CLIENT = 4;
50
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080051 private boolean mEnableTrafficStatsPoll = false;
52 private int mTrafficStatsPollToken = 0;
53 private long mTxPkts;
54 private long mRxPkts;
55 /* Tracks last reported data activity */
56 private int mDataActivity;
57
Irfan Sheriffc808a192013-03-05 09:46:36 -080058 private final List<Messenger> mClients = new ArrayList<Messenger>();
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080059 // err on the side of updating at boot since screen on broadcast may be missed
60 // the first time
61 private AtomicBoolean mScreenOn = new AtomicBoolean(true);
62 private final TrafficHandler mTrafficHandler;
63 private NetworkInfo mNetworkInfo;
64 private final String mInterface;
65
Irfan Sheriffc808a192013-03-05 09:46:36 -080066 WifiTrafficPoller(Context context, String iface) {
Irfan Sheriffb8c0e002013-02-20 14:19:54 -080067 mInterface = iface;
68 mTrafficHandler = new TrafficHandler();
69
70 IntentFilter filter = new IntentFilter();
71 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
72 filter.addAction(Intent.ACTION_SCREEN_OFF);
73 filter.addAction(Intent.ACTION_SCREEN_ON);
74
75 context.registerReceiver(
76 new BroadcastReceiver() {
77 @Override
78 public void onReceive(Context context, Intent intent) {
79 if (intent.getAction().equals(
80 WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
81 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
82 WifiManager.EXTRA_NETWORK_INFO);
83 } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
84 mScreenOn.set(false);
85 } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
86 mScreenOn.set(true);
87 }
88 evaluateTrafficStatsPolling();
89 }
90 }, filter);
91 }
92
Irfan Sheriffc808a192013-03-05 09:46:36 -080093 void addClient(Messenger client) {
94 Message.obtain(mTrafficHandler, ADD_CLIENT, client).sendToTarget();
95 }
96
97 void removeClient(Messenger client) {
98 Message.obtain(mTrafficHandler, REMOVE_CLIENT, client).sendToTarget();
99 }
100
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800101
102 private class TrafficHandler extends Handler {
103 public void handleMessage(Message msg) {
104 switch (msg.what) {
Irfan Sheriffc808a192013-03-05 09:46:36 -0800105 case ENABLE_TRAFFIC_STATS_POLL:
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800106 mEnableTrafficStatsPoll = (msg.arg1 == 1);
107 mTrafficStatsPollToken++;
108 if (mEnableTrafficStatsPoll) {
109 notifyOnDataActivity();
Irfan Sheriffc808a192013-03-05 09:46:36 -0800110 sendMessageDelayed(Message.obtain(this, TRAFFIC_STATS_POLL,
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800111 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
112 }
113 break;
Irfan Sheriffc808a192013-03-05 09:46:36 -0800114 case TRAFFIC_STATS_POLL:
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800115 if (msg.arg1 == mTrafficStatsPollToken) {
116 notifyOnDataActivity();
Irfan Sheriffc808a192013-03-05 09:46:36 -0800117 sendMessageDelayed(Message.obtain(this, TRAFFIC_STATS_POLL,
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800118 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS);
119 }
120 break;
Irfan Sheriffc808a192013-03-05 09:46:36 -0800121 case ADD_CLIENT:
122 mClients.add((Messenger) msg.obj);
123 break;
124 case REMOVE_CLIENT:
125 mClients.remove(msg.obj);
126 break;
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800127 }
128
129 }
130 }
131
132 private void evaluateTrafficStatsPolling() {
133 Message msg;
134 if (mNetworkInfo == null) return;
135 if (mNetworkInfo.getDetailedState() == CONNECTED && mScreenOn.get()) {
136 msg = Message.obtain(mTrafficHandler,
Irfan Sheriffc808a192013-03-05 09:46:36 -0800137 ENABLE_TRAFFIC_STATS_POLL, 1, 0);
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800138 } else {
139 msg = Message.obtain(mTrafficHandler,
Irfan Sheriffc808a192013-03-05 09:46:36 -0800140 ENABLE_TRAFFIC_STATS_POLL, 0, 0);
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800141 }
142 msg.sendToTarget();
143 }
144
145 private void notifyOnDataActivity() {
146 long sent, received;
147 long preTxPkts = mTxPkts, preRxPkts = mRxPkts;
148 int dataActivity = WifiManager.DATA_ACTIVITY_NONE;
149
150 mTxPkts = TrafficStats.getTxPackets(mInterface);
151 mRxPkts = TrafficStats.getRxPackets(mInterface);
152
153 if (preTxPkts > 0 || preRxPkts > 0) {
154 sent = mTxPkts - preTxPkts;
155 received = mRxPkts - preRxPkts;
156 if (sent > 0) {
157 dataActivity |= WifiManager.DATA_ACTIVITY_OUT;
158 }
159 if (received > 0) {
160 dataActivity |= WifiManager.DATA_ACTIVITY_IN;
161 }
162
163 if (dataActivity != mDataActivity && mScreenOn.get()) {
164 mDataActivity = dataActivity;
Irfan Sheriff302b06d2013-02-22 12:35:31 -0800165 for (Messenger client : mClients) {
166 Message msg = Message.obtain();
167 msg.what = WifiManager.DATA_ACTIVITY_NOTIFICATION;
168 msg.arg1 = mDataActivity;
169 try {
170 client.send(msg);
171 } catch (RemoteException e) {
172 // Failed to reach, skip
173 // Client removal is handled in WifiService
174 }
Irfan Sheriffb8c0e002013-02-20 14:19:54 -0800175 }
176 }
177 }
178 }
179
180 void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
181 pw.println("mEnableTrafficStatsPoll " + mEnableTrafficStatsPoll);
182 pw.println("mTrafficStatsPollToken " + mTrafficStatsPollToken);
183 pw.println("mTxPkts " + mTxPkts);
184 pw.println("mRxPkts " + mRxPkts);
185 pw.println("mDataActivity " + mDataActivity);
186 }
187
188}