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