WifiTrafficPoller.java revision da918df16e03ee19be62343313d954027d3eb3ab
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/** 42 * Polls for traffic stats and notifies the clients 43 */ 44public class WifiTrafficPoller { 45 46 private static final boolean DBG = false; 47 private static 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 private boolean mVerboseLoggingEnabled = false; 75 76 WifiTrafficPoller(Context context, Looper looper, String iface) { 77 mInterface = iface; 78 mTrafficHandler = new TrafficHandler(looper); 79 80 IntentFilter filter = new IntentFilter(); 81 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 82 filter.addAction(Intent.ACTION_SCREEN_OFF); 83 filter.addAction(Intent.ACTION_SCREEN_ON); 84 85 context.registerReceiver( 86 new BroadcastReceiver() { 87 @Override 88 public void onReceive(Context context, Intent intent) { 89 if (intent == null) { 90 return; 91 } 92 if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals( 93 intent.getAction())) { 94 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( 95 WifiManager.EXTRA_NETWORK_INFO); 96 } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { 97 mScreenOn.set(false); 98 } else if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) { 99 mScreenOn.set(true); 100 } 101 evaluateTrafficStatsPolling(); 102 } 103 }, filter); 104 } 105 106 void addClient(Messenger client) { 107 Message.obtain(mTrafficHandler, ADD_CLIENT, client).sendToTarget(); 108 } 109 110 void removeClient(Messenger client) { 111 Message.obtain(mTrafficHandler, REMOVE_CLIENT, client).sendToTarget(); 112 } 113 114 void enableVerboseLogging(int verbose) { 115 if (verbose > 0) { 116 mVerboseLoggingEnabled = true; 117 } else { 118 mVerboseLoggingEnabled = false; 119 } 120 } 121 122 private class TrafficHandler extends Handler { 123 public TrafficHandler(Looper looper) { 124 super(looper); 125 } 126 127 public void handleMessage(Message msg) { 128 switch (msg.what) { 129 case ENABLE_TRAFFIC_STATS_POLL: 130 mEnableTrafficStatsPoll = (msg.arg1 == 1); 131 if (mVerboseLoggingEnabled) { 132 Log.d(TAG, "ENABLE_TRAFFIC_STATS_POLL " 133 + mEnableTrafficStatsPoll + " Token " 134 + Integer.toString(mTrafficStatsPollToken)); 135 } 136 mTrafficStatsPollToken++; 137 if (mEnableTrafficStatsPoll) { 138 notifyOnDataActivity(); 139 sendMessageDelayed(Message.obtain(this, TRAFFIC_STATS_POLL, 140 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS); 141 } 142 break; 143 case TRAFFIC_STATS_POLL: 144 if (DBG) { 145 Log.d(TAG, "TRAFFIC_STATS_POLL " 146 + mEnableTrafficStatsPoll + " Token " 147 + Integer.toString(mTrafficStatsPollToken) 148 + " num clients " + mClients.size()); 149 } 150 if (msg.arg1 == mTrafficStatsPollToken) { 151 notifyOnDataActivity(); 152 sendMessageDelayed(Message.obtain(this, TRAFFIC_STATS_POLL, 153 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS); 154 } 155 break; 156 case ADD_CLIENT: 157 mClients.add((Messenger) msg.obj); 158 if (mVerboseLoggingEnabled) { 159 Log.d(TAG, "ADD_CLIENT: " 160 + Integer.toString(mClients.size())); 161 } 162 break; 163 case REMOVE_CLIENT: 164 mClients.remove(msg.obj); 165 break; 166 } 167 168 } 169 } 170 171 private void evaluateTrafficStatsPolling() { 172 Message msg; 173 if (mNetworkInfo == null) return; 174 if (mNetworkInfo.getDetailedState() == CONNECTED && mScreenOn.get()) { 175 msg = Message.obtain(mTrafficHandler, 176 ENABLE_TRAFFIC_STATS_POLL, 1, 0); 177 } else { 178 msg = Message.obtain(mTrafficHandler, 179 ENABLE_TRAFFIC_STATS_POLL, 0, 0); 180 } 181 msg.sendToTarget(); 182 } 183 184 private void notifyOnDataActivity() { 185 long sent, received; 186 long preTxPkts = mTxPkts, preRxPkts = mRxPkts; 187 int dataActivity = WifiManager.DATA_ACTIVITY_NONE; 188 189 mTxPkts = TrafficStats.getTxPackets(mInterface); 190 mRxPkts = TrafficStats.getRxPackets(mInterface); 191 192 if (DBG) { 193 Log.d(TAG, " packet count Tx=" 194 + Long.toString(mTxPkts) 195 + " Rx=" 196 + Long.toString(mRxPkts)); 197 } 198 199 if (preTxPkts > 0 || preRxPkts > 0) { 200 sent = mTxPkts - preTxPkts; 201 received = mRxPkts - preRxPkts; 202 if (sent > 0) { 203 dataActivity |= WifiManager.DATA_ACTIVITY_OUT; 204 } 205 if (received > 0) { 206 dataActivity |= WifiManager.DATA_ACTIVITY_IN; 207 } 208 209 if (dataActivity != mDataActivity && mScreenOn.get()) { 210 mDataActivity = dataActivity; 211 if (mVerboseLoggingEnabled) { 212 Log.e(TAG, "notifying of data activity " 213 + Integer.toString(mDataActivity)); 214 } 215 for (Messenger client : mClients) { 216 Message msg = Message.obtain(); 217 msg.what = WifiManager.DATA_ACTIVITY_NOTIFICATION; 218 msg.arg1 = mDataActivity; 219 try { 220 client.send(msg); 221 } catch (RemoteException e) { 222 // Failed to reach, skip 223 // Client removal is handled in WifiService 224 } 225 } 226 } 227 } 228 } 229 230 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 231 pw.println("mEnableTrafficStatsPoll " + mEnableTrafficStatsPoll); 232 pw.println("mTrafficStatsPollToken " + mTrafficStatsPollToken); 233 pw.println("mTxPkts " + mTxPkts); 234 pw.println("mRxPkts " + mRxPkts); 235 pw.println("mDataActivity " + mDataActivity); 236 } 237 238} 239