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