WifiTrafficPoller.java revision 8e14dcb9dc38149b4672eceb3fe22287ea4343a0
1/* 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 static android.net.NetworkInfo.DetailedState.CONNECTED; 20 21import android.content.BroadcastReceiver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.net.NetworkInfo; 26import android.net.TrafficStats; 27import android.net.wifi.WifiManager; 28import android.os.Handler; 29import android.os.Looper; 30import android.os.Message; 31import android.os.Messenger; 32import android.os.RemoteException; 33import android.util.Log; 34 35import java.io.FileDescriptor; 36import java.io.PrintWriter; 37import java.util.ArrayList; 38import java.util.List; 39import java.util.concurrent.atomic.AtomicBoolean; 40 41/* Polls for traffic stats and notifies the clients */ 42final class WifiTrafficPoller { 43 44 private boolean DBG = false; 45 private boolean VDBG = false; 46 47 private final String TAG = "WifiTrafficPoller"; 48 /** 49 * Interval in milliseconds between polling for traffic 50 * statistics 51 */ 52 private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000; 53 54 private static final int ENABLE_TRAFFIC_STATS_POLL = 1; 55 private static final int TRAFFIC_STATS_POLL = 2; 56 private static final int ADD_CLIENT = 3; 57 private static final int REMOVE_CLIENT = 4; 58 59 private boolean mEnableTrafficStatsPoll = false; 60 private int mTrafficStatsPollToken = 0; 61 private long mTxPkts; 62 private long mRxPkts; 63 /* Tracks last reported data activity */ 64 private int mDataActivity; 65 66 private final List<Messenger> mClients = new ArrayList<Messenger>(); 67 // err on the side of updating at boot since screen on broadcast may be missed 68 // the first time 69 private AtomicBoolean mScreenOn = new AtomicBoolean(true); 70 private final TrafficHandler mTrafficHandler; 71 private NetworkInfo mNetworkInfo; 72 private final String mInterface; 73 74 WifiTrafficPoller(Context context, Looper looper, String iface) { 75 mInterface = iface; 76 mTrafficHandler = new TrafficHandler(looper); 77 78 IntentFilter filter = new IntentFilter(); 79 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 80 filter.addAction(Intent.ACTION_SCREEN_OFF); 81 filter.addAction(Intent.ACTION_SCREEN_ON); 82 83 context.registerReceiver( 84 new BroadcastReceiver() { 85 @Override 86 public void onReceive(Context context, Intent intent) { 87 if (intent.getAction().equals( 88 WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 89 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( 90 WifiManager.EXTRA_NETWORK_INFO); 91 } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 92 mScreenOn.set(false); 93 } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { 94 mScreenOn.set(true); 95 } 96 evaluateTrafficStatsPolling(); 97 } 98 }, filter); 99 } 100 101 void addClient(Messenger client) { 102 Message.obtain(mTrafficHandler, ADD_CLIENT, client).sendToTarget(); 103 } 104 105 void removeClient(Messenger client) { 106 Message.obtain(mTrafficHandler, REMOVE_CLIENT, client).sendToTarget(); 107 } 108 109 void enableVerboseLogging(int verbose) { 110 if (verbose > 0 ) { 111 DBG = true; 112 } else { 113 DBG = false; 114 } 115 } 116 117 private class TrafficHandler extends Handler { 118 public TrafficHandler(Looper looper) { 119 super(looper); 120 } 121 122 public void handleMessage(Message msg) { 123 switch (msg.what) { 124 case ENABLE_TRAFFIC_STATS_POLL: 125 mEnableTrafficStatsPoll = (msg.arg1 == 1); 126 if (DBG) { 127 Log.e(TAG, "ENABLE_TRAFFIC_STATS_POLL " 128 + mEnableTrafficStatsPoll + " Token " 129 + Integer.toString(mTrafficStatsPollToken)); 130 } 131 mTrafficStatsPollToken++; 132 if (mEnableTrafficStatsPoll) { 133 notifyOnDataActivity(); 134 sendMessageDelayed(Message.obtain(this, TRAFFIC_STATS_POLL, 135 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS); 136 } 137 break; 138 case TRAFFIC_STATS_POLL: 139 if (VDBG) { 140 Log.e(TAG, "TRAFFIC_STATS_POLL " 141 + mEnableTrafficStatsPoll + " Token " 142 + Integer.toString(mTrafficStatsPollToken) 143 + " num clients " + mClients.size()); 144 } 145 if (msg.arg1 == mTrafficStatsPollToken) { 146 notifyOnDataActivity(); 147 sendMessageDelayed(Message.obtain(this, TRAFFIC_STATS_POLL, 148 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS); 149 } 150 break; 151 case ADD_CLIENT: 152 mClients.add((Messenger) msg.obj); 153 if (DBG) { 154 Log.e(TAG, "ADD_CLIENT: " 155 + Integer.toString(mClients.size())); 156 } 157 break; 158 case REMOVE_CLIENT: 159 mClients.remove(msg.obj); 160 break; 161 } 162 163 } 164 } 165 166 private void evaluateTrafficStatsPolling() { 167 Message msg; 168 if (mNetworkInfo == null) return; 169 if (mNetworkInfo.getDetailedState() == CONNECTED && mScreenOn.get()) { 170 msg = Message.obtain(mTrafficHandler, 171 ENABLE_TRAFFIC_STATS_POLL, 1, 0); 172 } else { 173 msg = Message.obtain(mTrafficHandler, 174 ENABLE_TRAFFIC_STATS_POLL, 0, 0); 175 } 176 msg.sendToTarget(); 177 } 178 179 private void notifyOnDataActivity() { 180 long sent, received; 181 long preTxPkts = mTxPkts, preRxPkts = mRxPkts; 182 int dataActivity = WifiManager.DATA_ACTIVITY_NONE; 183 184 mTxPkts = TrafficStats.getTxPackets(mInterface); 185 mRxPkts = TrafficStats.getRxPackets(mInterface); 186 187 if (VDBG) { 188 Log.e(TAG, " packet count Tx=" 189 + Long.toString(mTxPkts) 190 + " Rx=" 191 + Long.toString(mRxPkts)); 192 } 193 194 if (preTxPkts > 0 || preRxPkts > 0) { 195 sent = mTxPkts - preTxPkts; 196 received = mRxPkts - preRxPkts; 197 if (sent > 0) { 198 dataActivity |= WifiManager.DATA_ACTIVITY_OUT; 199 } 200 if (received > 0) { 201 dataActivity |= WifiManager.DATA_ACTIVITY_IN; 202 } 203 204 if (dataActivity != mDataActivity && mScreenOn.get()) { 205 mDataActivity = dataActivity; 206 if (DBG) { 207 Log.e(TAG, "notifying of data activity " 208 + Integer.toString(mDataActivity)); 209 } 210 for (Messenger client : mClients) { 211 Message msg = Message.obtain(); 212 msg.what = WifiManager.DATA_ACTIVITY_NOTIFICATION; 213 msg.arg1 = mDataActivity; 214 try { 215 client.send(msg); 216 } catch (RemoteException e) { 217 // Failed to reach, skip 218 // Client removal is handled in WifiService 219 } 220 } 221 } 222 } 223 } 224 225 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 226 pw.println("mEnableTrafficStatsPoll " + mEnableTrafficStatsPoll); 227 pw.println("mTrafficStatsPollToken " + mTrafficStatsPollToken); 228 pw.println("mTxPkts " + mTxPkts); 229 pw.println("mRxPkts " + mRxPkts); 230 pw.println("mDataActivity " + mDataActivity); 231 } 232 233} 234