WifiTrafficPoller.java revision f22d23092ab37286a5ef9d257d5bb32c421d2669
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; 31 32import java.io.FileDescriptor; 33import java.io.PrintWriter; 34import java.util.ArrayList; 35import java.util.List; 36import java.util.concurrent.atomic.AtomicBoolean; 37 38/* 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 46 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 51 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 58 private final List<Messenger> mClients = new ArrayList<Messenger>(); 59 // 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 66 WifiTrafficPoller(Context context, String iface) { 67 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 93 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 101 boolean shouldSwitchNetwork(int networkDelta) { 102 if (networkDelta > 0) 103 return true; 104 105 return false; 106 } 107 108 private class TrafficHandler extends Handler { 109 public void handleMessage(Message msg) { 110 switch (msg.what) { 111 case ENABLE_TRAFFIC_STATS_POLL: 112 mEnableTrafficStatsPoll = (msg.arg1 == 1); 113 mTrafficStatsPollToken++; 114 if (mEnableTrafficStatsPoll) { 115 notifyOnDataActivity(); 116 sendMessageDelayed(Message.obtain(this, TRAFFIC_STATS_POLL, 117 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS); 118 } 119 break; 120 case TRAFFIC_STATS_POLL: 121 if (msg.arg1 == mTrafficStatsPollToken) { 122 notifyOnDataActivity(); 123 sendMessageDelayed(Message.obtain(this, TRAFFIC_STATS_POLL, 124 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS); 125 } 126 break; 127 case ADD_CLIENT: 128 mClients.add((Messenger) msg.obj); 129 break; 130 case REMOVE_CLIENT: 131 mClients.remove(msg.obj); 132 break; 133 } 134 135 } 136 } 137 138 private void evaluateTrafficStatsPolling() { 139 Message msg; 140 if (mNetworkInfo == null) return; 141 if (mNetworkInfo.getDetailedState() == CONNECTED && mScreenOn.get()) { 142 msg = Message.obtain(mTrafficHandler, 143 ENABLE_TRAFFIC_STATS_POLL, 1, 0); 144 } else { 145 msg = Message.obtain(mTrafficHandler, 146 ENABLE_TRAFFIC_STATS_POLL, 0, 0); 147 } 148 msg.sendToTarget(); 149 } 150 151 private void notifyOnDataActivity() { 152 long sent, received; 153 long preTxPkts = mTxPkts, preRxPkts = mRxPkts; 154 int dataActivity = WifiManager.DATA_ACTIVITY_NONE; 155 156 mTxPkts = TrafficStats.getTxPackets(mInterface); 157 mRxPkts = TrafficStats.getRxPackets(mInterface); 158 159 if (preTxPkts > 0 || preRxPkts > 0) { 160 sent = mTxPkts - preTxPkts; 161 received = mRxPkts - preRxPkts; 162 if (sent > 0) { 163 dataActivity |= WifiManager.DATA_ACTIVITY_OUT; 164 } 165 if (received > 0) { 166 dataActivity |= WifiManager.DATA_ACTIVITY_IN; 167 } 168 169 if (dataActivity != mDataActivity && mScreenOn.get()) { 170 mDataActivity = dataActivity; 171 for (Messenger client : mClients) { 172 Message msg = Message.obtain(); 173 msg.what = WifiManager.DATA_ACTIVITY_NOTIFICATION; 174 msg.arg1 = mDataActivity; 175 try { 176 client.send(msg); 177 } catch (RemoteException e) { 178 // Failed to reach, skip 179 // Client removal is handled in WifiService 180 } 181 } 182 } 183 } 184 } 185 186 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 187 pw.println("mEnableTrafficStatsPoll " + mEnableTrafficStatsPoll); 188 pw.println("mTrafficStatsPollToken " + mTrafficStatsPollToken); 189 pw.println("mTxPkts " + mTxPkts); 190 pw.println("mRxPkts " + mRxPkts); 191 pw.println("mDataActivity " + mDataActivity); 192 } 193 194} 195