am e2a6d3df: Merge "Introduce network link quality statistics" into klp-dev

* commit 'e2a6d3df1257c1c04b1a14777bb7ee65f634bdc3':
  Introduce network link quality statistics
This commit is contained in:
Vinit Deshapnde
2013-08-22 09:21:45 -07:00
committed by Android Git Automerger
18 changed files with 1136 additions and 43 deletions

View File

@@ -16,6 +16,7 @@
package android.bluetooth;
import android.net.BaseNetworkStateTracker;
import android.os.IBinder;
import android.os.ServiceManager;
import android.os.INetworkManagementService;
@@ -54,7 +55,7 @@ import java.util.concurrent.atomic.AtomicReference;
*
* @hide
*/
public class BluetoothTetheringDataTracker implements NetworkStateTracker {
public class BluetoothTetheringDataTracker extends BaseNetworkStateTracker {
private static final String NETWORKTYPE = "BLUETOOTH_TETHER";
private static final String TAG = "BluetoothTethering";
private static final boolean DBG = true;
@@ -66,18 +67,12 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker {
private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
private final Object mLinkPropertiesLock = new Object();
private LinkProperties mLinkProperties;
private LinkCapabilities mLinkCapabilities;
private final Object mNetworkInfoLock = new Object();
private NetworkInfo mNetworkInfo;
private BluetoothPan mBluetoothPan;
private static String mRevTetheredIface;
/* For sending events to connectivity service handler */
private Handler mCsHandler;
protected Context mContext;
private static BluetoothTetheringDataTracker sInstance;
private BtdtHandler mBtdtHandler;
private AtomicReference<AsyncChannel> mAsyncChannel = new AtomicReference<AsyncChannel>(null);

View File

@@ -57,6 +57,10 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker {
mLinkCapabilities = new LinkCapabilities();
}
protected BaseNetworkStateTracker() {
// By default, let the sub classes construct everything
}
@Deprecated
protected Handler getTargetHandler() {
return mTarget;
@@ -73,29 +77,36 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker {
}
@Override
public final void startMonitoring(Context context, Handler target) {
public void startMonitoring(Context context, Handler target) {
mContext = Preconditions.checkNotNull(context);
mTarget = Preconditions.checkNotNull(target);
startMonitoringInternal();
}
protected abstract void startMonitoringInternal();
protected void startMonitoringInternal() {
}
@Override
public final NetworkInfo getNetworkInfo() {
public NetworkInfo getNetworkInfo() {
return new NetworkInfo(mNetworkInfo);
}
@Override
public final LinkProperties getLinkProperties() {
public LinkProperties getLinkProperties() {
return new LinkProperties(mLinkProperties);
}
@Override
public final LinkCapabilities getLinkCapabilities() {
public LinkCapabilities getLinkCapabilities() {
return new LinkCapabilities(mLinkCapabilities);
}
@Override
public LinkInfo getLinkInfo() {
return null;
}
@Override
public void captivePortalCheckComplete() {
// not implemented
@@ -176,4 +187,23 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker {
public void supplyMessenger(Messenger messenger) {
// not supported on this network
}
@Override
public String getNetworkInterfaceName() {
if (mLinkProperties != null) {
return mLinkProperties.getInterfaceName();
} else {
return null;
}
}
@Override
public void startSampling(SamplingDataTracker.SamplingSnapshot s) {
// nothing to do
}
@Override
public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
// nothing to do
}
}

View File

@@ -1442,4 +1442,43 @@ public class ConnectivityManager {
}
return null;
}
/**
* get the information about a specific network link
* @hide
*/
public LinkInfo getLinkInfo(int networkType) {
try {
LinkInfo li = mService.getLinkInfo(networkType);
return li;
} catch (RemoteException e) {
return null;
}
}
/**
* get the information of currently active network link
* @hide
*/
public LinkInfo getActiveLinkInfo() {
try {
LinkInfo li = mService.getActiveLinkInfo();
return li;
} catch (RemoteException e) {
return null;
}
}
/**
* get the information of all network links
* @hide
*/
public LinkInfo[] getAllLinkInfo() {
try {
LinkInfo[] li = mService.getAllLinkInfo();
return li;
} catch (RemoteException e) {
return null;
}
}
}

View File

@@ -29,18 +29,14 @@ import android.util.Slog;
*
* {@hide}
*/
public class DummyDataStateTracker implements NetworkStateTracker {
public class DummyDataStateTracker extends BaseNetworkStateTracker {
private static final String TAG = "DummyDataStateTracker";
private static final boolean DBG = true;
private static final boolean VDBG = false;
private NetworkInfo mNetworkInfo;
private boolean mTeardownRequested = false;
private Handler mTarget;
private Context mContext;
private LinkProperties mLinkProperties;
private LinkCapabilities mLinkCapabilities;
private boolean mPrivateDnsRouteSet = false;
private boolean mDefaultRouteSet = false;

View File

@@ -38,7 +38,7 @@ import java.util.concurrent.atomic.AtomicInteger;
* ConnectivityService.
* @hide
*/
public class EthernetDataTracker implements NetworkStateTracker {
public class EthernetDataTracker extends BaseNetworkStateTracker {
private static final String NETWORKTYPE = "ETHERNET";
private static final String TAG = "Ethernet";
@@ -48,15 +48,11 @@ public class EthernetDataTracker implements NetworkStateTracker {
private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
private static boolean mLinkUp;
private LinkProperties mLinkProperties;
private LinkCapabilities mLinkCapabilities;
private NetworkInfo mNetworkInfo;
private InterfaceObserver mInterfaceObserver;
private String mHwAddr;
/* For sending events to connectivity service handler */
private Handler mCsHandler;
private Context mContext;
private static EthernetDataTracker sInstance;
private static String sIfaceMatch = "";

View File

@@ -16,6 +16,7 @@
package android.net;
import android.net.LinkInfo;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkQuotaInfo;
@@ -145,4 +146,11 @@ interface IConnectivityManager
String getMobileProvisioningUrl();
String getMobileRedirectedProvisioningUrl();
LinkInfo getLinkInfo(int networkType);
LinkInfo getActiveLinkInfo();
LinkInfo[] getAllLinkInfo();
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
parcelable LinkInfo;

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Class that represents useful attributes of generic network links
* such as the upload/download throughput or packet error rate.
* Generally speaking, you should be dealing with instances of
* LinkInfo subclasses, such as {@link android.net.#WifiLinkInfo}
* or {@link android.net.#MobileLinkInfo} which provide additional
* information.
* @hide
*/
public class LinkInfo implements Parcelable
{
public static final int UNKNOWN = Integer.MAX_VALUE;
public static final int NORMALIZED_MIN_SIGNAL_STRENGTH = 0;
public static final int NORMALIZED_MAX_SIGNAL_STRENGTH = 99;
public static final int NORMALIZED_SIGNAL_STRENGTH_RANGE = NORMALIZED_MAX_SIGNAL_STRENGTH + 1;
/* Network type as defined by ConnectivityManager */
public int mNetworkType = ConnectivityManager.TYPE_NONE;
public int mNormalizedSignalStrength = UNKNOWN;
public int mPacketCount = UNKNOWN;
public int mPacketErrorCount = UNKNOWN;
public int mTheoreticalTxBandwidth = UNKNOWN;
public int mTheoreticalRxBandwidth = UNKNOWN;
public int mTheoreticalLatency = UNKNOWN;
/* Timestamp when last sample was made available */
public long mLastDataSampleTime = UNKNOWN;
/* Sample duration in millisecond */
public int mDataSampleDuration = UNKNOWN;
public LinkInfo() {
}
/**
* Implement the Parcelable interface
* @hide
*/
public int describeContents() {
return 0;
}
/**
* Implement the Parcelable interface.
*/
protected static final int OBJECT_TYPE_LINKINFO = 1;
protected static final int OBJECT_TYPE_WIFI_LINKINFO = 2;
protected static final int OBJECT_TYPE_MOBILE_LINKINFO = 3;
public void writeToParcel(Parcel dest, int flags) {
writeToParcel(dest, flags, OBJECT_TYPE_LINKINFO);
}
public void writeToParcel(Parcel dest, int flags, int objectType) {
dest.writeInt(objectType);
dest.writeInt(mNetworkType);
dest.writeInt(mNormalizedSignalStrength);
dest.writeInt(mPacketCount);
dest.writeInt(mPacketErrorCount);
dest.writeInt(mTheoreticalTxBandwidth);
dest.writeInt(mTheoreticalRxBandwidth);
dest.writeInt(mTheoreticalLatency);
dest.writeLong(mLastDataSampleTime);
dest.writeInt(mDataSampleDuration);
}
public static final Creator<LinkInfo> CREATOR =
new Creator<LinkInfo>() {
public LinkInfo createFromParcel(Parcel in) {
int objectType = in.readInt();
if (objectType == OBJECT_TYPE_LINKINFO) {
LinkInfo li = new LinkInfo();
li.initializeFromParcel(in);
return li;
} else if (objectType == OBJECT_TYPE_WIFI_LINKINFO) {
return WifiLinkInfo.createFromParcelBody(in);
} else if (objectType == OBJECT_TYPE_MOBILE_LINKINFO) {
return MobileLinkInfo.createFromParcelBody(in);
} else {
return null;
}
}
public LinkInfo[] newArray(int size) {
return new LinkInfo[size];
}
};
protected void initializeFromParcel(Parcel in) {
mNetworkType = in.readInt();
mNormalizedSignalStrength = in.readInt();
mPacketCount = in.readInt();
mPacketErrorCount = in.readInt();
mTheoreticalTxBandwidth = in.readInt();
mTheoreticalRxBandwidth = in.readInt();
mTheoreticalLatency = in.readInt();
mLastDataSampleTime = in.readLong();
mDataSampleDuration = in.readInt();
}
}

View File

@@ -18,4 +18,3 @@
package android.net;
parcelable LinkProperties;

View File

@@ -28,6 +28,8 @@ import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Slog;
@@ -49,7 +51,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
* {@hide}
*/
public class MobileDataStateTracker implements NetworkStateTracker {
public class MobileDataStateTracker extends BaseNetworkStateTracker {
private static final String TAG = "MobileDataStateTracker";
private static final boolean DBG = true;
@@ -59,12 +61,8 @@ public class MobileDataStateTracker implements NetworkStateTracker {
private ITelephony mPhoneService;
private String mApnType;
private NetworkInfo mNetworkInfo;
private boolean mTeardownRequested = false;
private Handler mTarget;
private Context mContext;
private LinkProperties mLinkProperties;
private LinkCapabilities mLinkCapabilities;
private boolean mPrivateDnsRouteSet = false;
private boolean mDefaultRouteSet = false;
@@ -78,6 +76,10 @@ public class MobileDataStateTracker implements NetworkStateTracker {
private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false);
private SignalStrength mSignalStrength;
private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker();
/**
* Create a new MobileDataStateTracker
* @param netType the ConnectivityManager network type
@@ -108,8 +110,19 @@ public class MobileDataStateTracker implements NetworkStateTracker {
mContext.registerReceiver(new MobileDataStateReceiver(), filter);
mMobileDataState = PhoneConstants.DataState.DISCONNECTED;
TelephonyManager tm = (TelephonyManager)mContext.getSystemService(
Context.TELEPHONY_SERVICE);
tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
}
private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
mSignalStrength = signalStrength;
}
};
static class MdstHandler extends Handler {
private MobileDataStateTracker mMdst;
@@ -251,6 +264,30 @@ public class MobileDataStateTracker implements NetworkStateTracker {
setDetailedState(DetailedState.CONNECTED, reason, apnName);
break;
}
if (VDBG) {
Slog.d(TAG, "TelephonyMgr.DataConnectionStateChanged");
if (mNetworkInfo != null) {
Slog.d(TAG, "NetworkInfo = " + mNetworkInfo.toString());
Slog.d(TAG, "subType = " + String.valueOf(mNetworkInfo.getSubtype()));
Slog.d(TAG, "subType = " + mNetworkInfo.getSubtypeName());
}
if (mLinkProperties != null) {
Slog.d(TAG, "LinkProperties = " + mLinkProperties.toString());
} else {
Slog.d(TAG, "LinkProperties = " );
}
if (mLinkCapabilities != null) {
Slog.d(TAG, "LinkCapabilities = " + mLinkCapabilities.toString());
} else {
Slog.d(TAG, "LinkCapabilities = " );
}
}
/* lets not sample traffic data across state changes */
mSamplingDataTracker.resetSamplingData();
} else {
// There was no state change. Check if LinkProperties has been updated.
if (TextUtils.equals(reason, PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) {
@@ -283,7 +320,7 @@ public class MobileDataStateTracker implements NetworkStateTracker {
String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY);
if (DBG) {
log("Received " + intent.getAction() +
" broadcast" + reason == null ? "" : "(" + reason + ")");
" broadcast" + (reason == null ? "" : "(" + reason + ")"));
}
setDetailedState(DetailedState.FAILED, reason, apnName);
} else {
@@ -557,7 +594,7 @@ public class MobileDataStateTracker implements NetworkStateTracker {
return writer.toString();
}
/**
/**
* Internal method supporting the ENABLE_MMS feature.
* @param apnType the type of APN to be enabled or disabled (e.g., mms)
* @param enable {@code true} to enable the specified APN type,
@@ -617,9 +654,11 @@ public class MobileDataStateTracker implements NetworkStateTracker {
}
}
/**
* @see android.net.NetworkStateTracker#getLinkProperties()
*/
@Override
public LinkProperties getLinkProperties() {
return new LinkProperties(mLinkProperties);
}
@@ -627,6 +666,7 @@ public class MobileDataStateTracker implements NetworkStateTracker {
/**
* @see android.net.NetworkStateTracker#getLinkCapabilities()
*/
@Override
public LinkCapabilities getLinkCapabilities() {
return new LinkCapabilities(mLinkCapabilities);
}
@@ -648,4 +688,152 @@ public class MobileDataStateTracker implements NetworkStateTracker {
static private void sloge(String s) {
Slog.e(TAG, s);
}
@Override
public LinkInfo getLinkInfo() {
if (mNetworkInfo == null || mNetworkInfo.getType() == ConnectivityManager.TYPE_NONE) {
// no data available yet; just return
return null;
}
MobileLinkInfo li = new MobileLinkInfo();
li.mNetworkType = mNetworkInfo.getType();
mSamplingDataTracker.setCommonLinkInfoFields(li);
if (mNetworkInfo.getSubtype() != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
li.mMobileNetworkType = mNetworkInfo.getSubtype();
NetworkDataEntry entry = getNetworkDataEntry(mNetworkInfo.getSubtype());
if (entry != null) {
li.mTheoreticalRxBandwidth = entry.downloadBandwidth;
li.mTheoreticalRxBandwidth = entry.uploadBandwidth;
li.mTheoreticalLatency = entry.latency;
}
if (mSignalStrength != null) {
li.mNormalizedSignalStrength = getNormalizedSignalStrength(
li.mMobileNetworkType, mSignalStrength);
}
}
SignalStrength ss = mSignalStrength;
if (ss != null) {
li.mRssi = ss.getGsmSignalStrength();
li.mGsmErrorRate = ss.getGsmBitErrorRate();
li.mCdmaDbm = ss.getCdmaDbm();
li.mCdmaEcio = ss.getCdmaEcio();
li.mEvdoDbm = ss.getEvdoDbm();
li.mEvdoEcio = ss.getEvdoEcio();
li.mEvdoSnr = ss.getEvdoSnr();
li.mLteSignalStrength = ss.getLteSignalStrength();
li.mLteRsrp = ss.getLteRsrp();
li.mLteRsrq = ss.getLteRsrq();
li.mLteRssnr = ss.getLteRssnr();
li.mLteCqi = ss.getLteCqi();
}
if (VDBG) {
Slog.d(TAG, "Returning LinkInfo with"
+ " MobileNetworkType = " + String.valueOf(li.mMobileNetworkType)
+ " Theoretical Rx BW = " + String.valueOf(li.mTheoreticalRxBandwidth)
+ " gsm Signal Strength = " + String.valueOf(li.mRssi)
+ " cdma Signal Strength = " + String.valueOf(li.mCdmaDbm)
+ " evdo Signal Strength = " + String.valueOf(li.mEvdoDbm)
+ " Lte Signal Strength = " + String.valueOf(li.mLteSignalStrength));
}
return li;
}
static class NetworkDataEntry {
public int networkType;
public int downloadBandwidth; // in kbps
public int uploadBandwidth; // in kbps
public int latency; // in millisecond
NetworkDataEntry(int i1, int i2, int i3, int i4) {
networkType = i1;
downloadBandwidth = i2;
uploadBandwidth = i3;
latency = i4;
}
}
private static NetworkDataEntry [] mTheoreticalBWTable = new NetworkDataEntry[] {
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EDGE, 237, 118, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_GPRS, 48, 40, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_UMTS, 384, 64, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSDPA, 14400, -1, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSUPA, 14400, 5760, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPA, 14400, 5760, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPAP, 21000, 5760, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_CDMA, -1, -1, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_1xRTT, -1, -1, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_0, 2468, 153, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_A, 3072, 1800, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_B, 14700, 1800, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_IDEN, -1, -1, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_LTE, 100000, 50000, -1),
new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EHRPD, -1, -1, -1),
};
private static NetworkDataEntry getNetworkDataEntry(int networkType) {
for (NetworkDataEntry entry : mTheoreticalBWTable) {
if (entry.networkType == networkType) {
return entry;
}
}
Slog.e(TAG, "Could not find Theoretical BW entry for " + String.valueOf(networkType));
return null;
}
private static int getNormalizedSignalStrength(int networkType, SignalStrength ss) {
int level;
switch(networkType) {
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_GPRS:
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_HSPAP:
level = ss.getGsmLevel();
break;
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_1xRTT:
level = ss.getCdmaLevel();
break;
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
level = ss.getEvdoLevel();
break;
case TelephonyManager.NETWORK_TYPE_LTE:
level = ss.getLteLevel();
break;
case TelephonyManager.NETWORK_TYPE_IDEN:
case TelephonyManager.NETWORK_TYPE_EHRPD:
default:
return LinkInfo.UNKNOWN;
}
return (level * LinkInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE) /
SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
}
@Override
public void startSampling(SamplingDataTracker.SamplingSnapshot s) {
mSamplingDataTracker.startSampling(s);
}
@Override
public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
mSamplingDataTracker.stopSampling(s);
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.os.Parcel;
import android.net.LinkInfo;
/**
* Class that represents useful attributes of mobile network links
* such as the upload/download throughput or error rate etc.
* @hide
*/
public final class MobileLinkInfo extends LinkInfo
{
// Represents TelephonyManager.NetworkType
public int mMobileNetworkType = UNKNOWN;
public int mRssi = UNKNOWN;
public int mGsmErrorRate = UNKNOWN;
public int mCdmaDbm = UNKNOWN;
public int mCdmaEcio = UNKNOWN;
public int mEvdoDbm = UNKNOWN;
public int mEvdoEcio = UNKNOWN;
public int mEvdoSnr = UNKNOWN;
public int mLteSignalStrength = UNKNOWN;
public int mLteRsrp = UNKNOWN;
public int mLteRsrq = UNKNOWN;
public int mLteRssnr = UNKNOWN;
public int mLteCqi = UNKNOWN;
/**
* Implement the Parcelable interface.
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags, OBJECT_TYPE_MOBILE_LINKINFO);
dest.writeInt(mMobileNetworkType);
dest.writeInt(mRssi);
dest.writeInt(mGsmErrorRate);
dest.writeInt(mCdmaDbm);
dest.writeInt(mCdmaEcio);
dest.writeInt(mEvdoDbm);
dest.writeInt(mEvdoEcio);
dest.writeInt(mEvdoSnr);
dest.writeInt(mLteSignalStrength);
dest.writeInt(mLteRsrp);
dest.writeInt(mLteRsrq);
dest.writeInt(mLteRssnr);
dest.writeInt(mLteCqi);
}
/* Un-parceling helper */
public static MobileLinkInfo createFromParcelBody(Parcel in) {
MobileLinkInfo li = new MobileLinkInfo();
li.initializeFromParcel(in);
li.mMobileNetworkType = in.readInt();
li.mRssi = in.readInt();
li.mGsmErrorRate = in.readInt();
li.mCdmaDbm = in.readInt();
li.mCdmaEcio = in.readInt();
li.mEvdoDbm = in.readInt();
li.mEvdoEcio = in.readInt();
li.mEvdoSnr = in.readInt();
li.mLteSignalStrength = in.readInt();
li.mLteRsrp = in.readInt();
li.mLteRsrq = in.readInt();
li.mLteRssnr = in.readInt();
li.mLteCqi = in.readInt();
return li;
}
}

View File

@@ -83,7 +83,6 @@ public interface NetworkStateTracker {
*/
public static final int EVENT_NETWORK_DISCONNECTED = BASE_NETWORK_STATE_TRACKER + 5;
/**
* -------------------------------------------------------------
* Control Interface
@@ -119,6 +118,12 @@ public interface NetworkStateTracker {
*/
public LinkCapabilities getLinkCapabilities();
/**
* Get interesting information about this network link
* @return a copy of link information, null if not available
*/
public LinkInfo getLinkInfo();
/**
* Return the system properties name associated with the tcp buffer sizes
* for this network.
@@ -234,4 +239,20 @@ public interface NetworkStateTracker {
* the underlying network specific code.
*/
public void supplyMessenger(Messenger messenger);
/*
* Network interface name that we'll lookup for sampling data
*/
public String getNetworkInterfaceName();
/*
* Save the starting sample
*/
public void startSampling(SamplingDataTracker.SamplingSnapshot s);
/*
* Save the ending sample
*/
public void stopSampling(SamplingDataTracker.SamplingSnapshot s);
}

View File

@@ -0,0 +1,295 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.os.SystemClock;
import android.util.Slog;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
/**
* @hide
*/
public class SamplingDataTracker
{
private static final boolean DBG = false;
private static final String TAG = "SamplingDataTracker";
public static class SamplingSnapshot
{
public int mTxByteCount;
public int mRxByteCount;
public int mTxPacketCount;
public int mRxPacketCount;
public int mTxPacketErrorCount;
public int mRxPacketErrorCount;
public long mTimestamp;
}
public static void getSamplingSnapshots(Map<String, SamplingSnapshot> mapIfaceToSample) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("/proc/net/dev"));
// Skip over the line bearing column titles (there are 2 lines)
String line;
reader.readLine();
reader.readLine();
while ((line = reader.readLine()) != null) {
// remove leading whitespace
line = line.trim();
String[] tokens = line.split("[ ]+");
if (tokens.length < 17) {
continue;
}
/* column format is
* Interface (Recv)bytes packets errs drop fifo frame compressed multicast \
* (Transmit)bytes packets errs drop fifo colls carrier compress
*/
String currentIface = tokens[0].split(":")[0];
if (DBG) Slog.d(TAG, "Found data for interface " + currentIface);
if (mapIfaceToSample.containsKey(currentIface)) {
SamplingSnapshot ss = new SamplingSnapshot();
ss.mTxByteCount = Integer.parseInt(tokens[1]);
ss.mTxPacketCount = Integer.parseInt(tokens[2]);
ss.mTxPacketErrorCount = Integer.parseInt(tokens[3]);
ss.mRxByteCount = Integer.parseInt(tokens[9]);
ss.mRxPacketCount = Integer.parseInt(tokens[10]);
ss.mRxPacketErrorCount = Integer.parseInt(tokens[11]);
ss.mTimestamp = SystemClock.elapsedRealtime();
if (DBG) {
Slog.d(TAG, "Interface = " + currentIface);
Slog.d(TAG, "ByteCount = " + String.valueOf(ss.mTxByteCount));
Slog.d(TAG, "TxPacketCount = " + String.valueOf(ss.mTxPacketCount));
Slog.d(TAG, "TxPacketErrorCount = "
+ String.valueOf(ss.mTxPacketErrorCount));
Slog.d(TAG, "RxByteCount = " + String.valueOf(ss.mRxByteCount));
Slog.d(TAG, "RxPacketCount = " + String.valueOf(ss.mRxPacketCount));
Slog.d(TAG, "RxPacketErrorCount = "
+ String.valueOf(ss.mRxPacketErrorCount));
Slog.d(TAG, "Timestamp = " + String.valueOf(ss.mTimestamp));
Slog.d(TAG, "---------------------------");
}
mapIfaceToSample.put(currentIface, ss);
}
}
if (DBG) {
Iterator it = mapIfaceToSample.entrySet().iterator();
while (it.hasNext()) {
Map.Entry kvpair = (Map.Entry)it.next();
if (kvpair.getValue() == null) {
Slog.d(TAG, "could not find snapshot for interface " + kvpair.getKey());
}
}
}
} catch(FileNotFoundException e) {
Slog.e(TAG, "could not find /proc/net/dev");
} catch (IOException e) {
Slog.e(TAG, "could not read /proc/net/dev");
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
Slog.e(TAG, "could not close /proc/net/dev");
}
}
}
// Snapshots from previous sampling interval
private SamplingSnapshot mBeginningSample;
private SamplingSnapshot mEndingSample;
// Starting snapshot of current interval
private SamplingSnapshot mLastSample;
// Protects sampling data from concurrent access
public final Object mSamplingDataLock = new Object();
// We need long enough time for a good sample
private final int MINIMUM_SAMPLING_INTERVAL = 15 * 1000;
// statistics is useless unless we have enough data
private final int MINIMUM_SAMPLED_PACKETS = 30;
public void startSampling(SamplingSnapshot s) {
synchronized(mSamplingDataLock) {
mLastSample = s;
}
}
public void stopSampling(SamplingSnapshot s) {
synchronized(mSamplingDataLock) {
if (mLastSample != null) {
if (s.mTimestamp - mLastSample.mTimestamp > MINIMUM_SAMPLING_INTERVAL
&& getSampledPacketCount(mLastSample, s) > MINIMUM_SAMPLED_PACKETS) {
mBeginningSample = mLastSample;
mEndingSample = s;
mLastSample = null;
} else {
if (DBG) Slog.d(TAG, "Throwing current sample away because it is too small");
}
}
}
}
public void resetSamplingData() {
if (DBG) Slog.d(TAG, "Resetting sampled network data");
synchronized(mSamplingDataLock) {
// We could just take another sample here and treat it as an
// 'ending sample' effectively shortening sampling interval, but that
// requires extra work (specifically, reading the sample needs to be
// done asynchronously)
mLastSample = null;
}
}
public int getSampledTxByteCount() {
synchronized(mSamplingDataLock) {
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mTxByteCount - mBeginningSample.mTxByteCount;
} else {
return LinkInfo.UNKNOWN;
}
}
}
public int getSampledTxPacketCount() {
synchronized(mSamplingDataLock) {
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mTxPacketCount - mBeginningSample.mTxPacketCount;
} else {
return LinkInfo.UNKNOWN;
}
}
}
public int getSampledTxPacketErrorCount() {
synchronized(mSamplingDataLock) {
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mTxPacketErrorCount - mBeginningSample.mTxPacketErrorCount;
} else {
return LinkInfo.UNKNOWN;
}
}
}
public int getSampledRxByteCount() {
synchronized(mSamplingDataLock) {
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mRxByteCount - mBeginningSample.mRxByteCount;
} else {
return LinkInfo.UNKNOWN;
}
}
}
public int getSampledRxPacketCount() {
synchronized(mSamplingDataLock) {
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mRxPacketCount - mBeginningSample.mRxPacketCount;
} else {
return LinkInfo.UNKNOWN;
}
}
}
public int getSampledPacketCount() {
return getSampledPacketCount(mBeginningSample, mEndingSample);
}
public int getSampledPacketCount(SamplingSnapshot begin, SamplingSnapshot end) {
if (begin != null && end != null) {
int rxPacketCount = end.mRxPacketCount - begin.mRxPacketCount;
int txPacketCount = end.mTxPacketCount - begin.mTxPacketCount;
return rxPacketCount + txPacketCount;
} else {
return LinkInfo.UNKNOWN;
}
}
public int getSampledPacketErrorCount() {
if (mBeginningSample != null && mEndingSample != null) {
int rxPacketErrorCount = getSampledRxPacketErrorCount();
int txPacketErrorCount = getSampledTxPacketErrorCount();
return rxPacketErrorCount + txPacketErrorCount;
} else {
return LinkInfo.UNKNOWN;
}
}
public int getSampledRxPacketErrorCount() {
synchronized(mSamplingDataLock) {
if (mBeginningSample != null && mEndingSample != null) {
return mEndingSample.mRxPacketErrorCount - mBeginningSample.mRxPacketErrorCount;
} else {
return LinkInfo.UNKNOWN;
}
}
}
public long getSampleTimestamp() {
synchronized(mSamplingDataLock) {
if (mEndingSample != null) {
return mEndingSample.mTimestamp;
} else {
return LinkInfo.UNKNOWN;
}
}
}
public int getSampleDuration() {
synchronized(mSamplingDataLock) {
if (mBeginningSample != null && mEndingSample != null) {
return (int) (mEndingSample.mTimestamp - mBeginningSample.mTimestamp);
} else {
return LinkInfo.UNKNOWN;
}
}
}
public void setCommonLinkInfoFields(LinkInfo li) {
synchronized(mSamplingDataLock) {
li.mLastDataSampleTime = getSampleTimestamp();
li.mDataSampleDuration = getSampleDuration();
li.mPacketCount = getSampledPacketCount();
li.mPacketErrorCount = getSampledPacketErrorCount();
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.os.Parcel;
import android.net.LinkInfo;
/**
* Class that represents useful attributes of wifi network links
* such as the upload/download throughput or error rate etc.
* @hide
*/
public final class WifiLinkInfo extends LinkInfo
{
/**
* Type enumerations for Wifi Network
*/
/* Indicates Wifi network type such as b/g etc*/
public int mType = UNKNOWN;
public String mBssid;
/* Rssi found by scans */
public int mRssi = UNKNOWN;
/* packet statistics */
public int mTxGood = UNKNOWN;
public int mTxBad = UNKNOWN;
/**
* Implement the Parcelable interface.
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags, OBJECT_TYPE_WIFI_LINKINFO);
dest.writeInt(mType);
dest.writeInt(mRssi);
dest.writeInt(mTxGood);
dest.writeInt(mTxBad);
dest.writeString(mBssid);
}
/* Un-parceling helper */
public static WifiLinkInfo createFromParcelBody(Parcel in) {
WifiLinkInfo li = new WifiLinkInfo();
li.initializeFromParcel(in);
li.mType = in.readInt();
li.mRssi = in.readInt();
li.mTxGood = in.readInt();
li.mTxBad = in.readInt();
li.mBssid = in.readString();
return li;
}
}

View File

@@ -5431,6 +5431,17 @@ public final class Settings {
*/
public static final String CONNECTIVITY_CHANGE_DELAY = "connectivity_change_delay";
/**
* Network sampling interval, in seconds. We'll generate link information
* about bytes/packets sent and error rates based on data sampled in this interval
*
* @hide
*/
public static final String CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS =
"connectivity_sampling_interval_in_seconds";
/**
* The series of successively longer delays used in retrying to download PAC file.
* Last delay is used between successful PAC downloads.

View File

@@ -229,6 +229,8 @@
<protected-broadcast android:name="android.net.conn.TETHER_STATE_CHANGED" />
<protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" />
<protected-broadcast android:name="android.net.conn.NETWORK_CONDITIONS_MEASURED" />
<protected-brodcast
android:name="android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED" />
<protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE" />
<protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE" />
<protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" />

View File

@@ -31,6 +31,7 @@ import static android.net.ConnectivityManager.isNetworkTypeValid;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -56,6 +57,7 @@ import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.LinkInfo;
import android.net.LinkProperties.CompareResult;
import android.net.MobileDataStateTracker;
import android.net.NetworkConfig;
@@ -68,6 +70,7 @@ import android.net.NetworkUtils;
import android.net.Proxy;
import android.net.ProxyProperties;
import android.net.RouteInfo;
import android.net.SamplingDataTracker;
import android.net.Uri;
import android.net.wifi.WifiStateTracker;
import android.net.wimax.WimaxManagerConstants;
@@ -144,8 +147,10 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
@@ -174,6 +179,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private static final String FAIL_FAST_TIME_MS =
"persist.radio.fail_fast_time_ms";
private static final String ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED =
"android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED";
private static final int SAMPLE_INTERVAL_ELAPSED_REQURST_CODE = 0;
private PendingIntent mSampleIntervalElapsedIntent;
// Set network sampling interval at 12 minutes, this way, even if the timers get
// aggregated, it will fire at around 15 minutes, which should allow us to
// aggregate this timer with other timers (specially the socket keep alive timers)
private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 12 * 60);
// start network sampling a minute after booting ...
private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 60);
AlarmManager mAlarmManager;
// used in recursive route setting to add gateways for the host for which
// a host route was requested.
private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10;
@@ -326,6 +348,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14;
/**
* user internally to indicate that data sampling interval is up
*/
private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15;
/** Handler used for internal events. */
private InternalHandler mHandler;
/** Handler used for incoming {@link NetworkStateTracker} events. */
@@ -392,6 +419,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
List mProtectedNetworks;
private DataConnectionStats mDataConnectionStats;
private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0);
TelephonyManager mTelephonyManager;
@@ -634,6 +662,29 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mDataConnectionStats = new DataConnectionStats(mContext);
mDataConnectionStats.startMonitoring();
// start network sampling ..
Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED, null);
mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext,
SAMPLE_INTERVAL_ELAPSED_REQURST_CODE, intent, 0);
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED);
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED)) {
mHandler.sendMessage(mHandler.obtainMessage
(EVENT_SAMPLE_INTERVAL_ELAPSED));
}
}
},
new IntentFilter(filter));
mPacManager = new PacManager(mContext);
}
@@ -1911,6 +1962,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// if (mActiveDefaultNetwork != -1) {
// currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority;
// }
for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
if (checkType == prevNetType) continue;
if (mNetConfigs[checkType] == null) continue;
@@ -1925,6 +1977,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// optimization should work and we need to investigate why it doesn't work.
// This could be related to how DEACTIVATE_DATA_CALL is reporting its
// complete before it is really complete.
// if (!mNetTrackers[checkType].isAvailable()) continue;
// if (currentPriority >= mNetConfigs[checkType].mPriority) continue;
@@ -2520,12 +2573,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
/**
/**
* Reads the network specific TCP buffer sizes from SystemProperties
* net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
* wide use
*/
private void updateNetworkSettings(NetworkStateTracker nt) {
private void updateNetworkSettings(NetworkStateTracker nt) {
String key = nt.getTcpBufferSizesPropName();
String bufferSizes = key == null ? null : SystemProperties.get(key);
@@ -2547,7 +2600,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
/**
/**
* Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
* which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
*
@@ -2956,6 +3009,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
+ " != tag:" + tag);
}
}
case EVENT_SAMPLE_INTERVAL_ELAPSED:
handleNetworkSamplingTimeout();
break;
}
}
}
@@ -4357,4 +4413,92 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
};
@Override
public LinkInfo getLinkInfo(int networkType) {
enforceAccessPermission();
if (isNetworkTypeValid(networkType)) {
return mNetTrackers[networkType].getLinkInfo();
} else {
return null;
}
}
@Override
public LinkInfo getActiveLinkInfo() {
enforceAccessPermission();
if (isNetworkTypeValid(mActiveDefaultNetwork)) {
return mNetTrackers[mActiveDefaultNetwork].getLinkInfo();
} else {
return null;
}
}
@Override
public LinkInfo[] getAllLinkInfo() {
enforceAccessPermission();
final ArrayList<LinkInfo> result = Lists.newArrayList();
for (NetworkStateTracker tracker : mNetTrackers) {
if (tracker != null) {
LinkInfo li = tracker.getLinkInfo();
if (li != null) {
result.add(li);
}
}
}
return result.toArray(new LinkInfo[result.size()]);
}
/* Infrastructure for network sampling */
private void handleNetworkSamplingTimeout() {
log("Sampling interval elapsed, updating statistics ..");
// initialize list of interfaces ..
Map<String, SamplingDataTracker.SamplingSnapshot> mapIfaceToSample =
new HashMap<String, SamplingDataTracker.SamplingSnapshot>();
for (NetworkStateTracker tracker : mNetTrackers) {
if (tracker != null) {
String ifaceName = tracker.getNetworkInterfaceName();
if (ifaceName != null) {
mapIfaceToSample.put(ifaceName, null);
}
}
}
// Read samples for all interfaces
SamplingDataTracker.getSamplingSnapshots(mapIfaceToSample);
// process samples for all networks
for (NetworkStateTracker tracker : mNetTrackers) {
if (tracker != null) {
String ifaceName = tracker.getNetworkInterfaceName();
SamplingDataTracker.SamplingSnapshot ss = mapIfaceToSample.get(ifaceName);
if (ss != null) {
// end the previous sampling cycle
tracker.stopSampling(ss);
// start a new sampling cycle ..
tracker.startSampling(ss);
}
}
}
log("Done.");
int samplingIntervalInSeconds = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
DEFAULT_SAMPLING_INTERVAL_IN_SECONDS);
if (DBG) log("Setting timer for " + String.valueOf(samplingIntervalInSeconds) + "seconds");
setAlarm(samplingIntervalInSeconds * 1000, mSampleIntervalElapsedIntent);
}
void setAlarm(int timeoutInMilliseconds, PendingIntent intent) {
long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds;
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent);
}
}

View File

@@ -20,11 +20,14 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.BaseNetworkStateTracker;
import android.net.LinkCapabilities;
import android.net.LinkInfo;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkStateTracker;
import android.net.SamplingDataTracker;
import android.net.WifiLinkInfo;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
@@ -37,7 +40,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
* @hide
*/
public class WifiStateTracker implements NetworkStateTracker {
public class WifiStateTracker extends BaseNetworkStateTracker {
private static final String NETWORKTYPE = "WIFI";
private static final String TAG = "WifiStateTracker";
@@ -48,17 +51,17 @@ public class WifiStateTracker implements NetworkStateTracker {
private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
private LinkProperties mLinkProperties;
private LinkCapabilities mLinkCapabilities;
private NetworkInfo mNetworkInfo;
private NetworkInfo.State mLastState = NetworkInfo.State.UNKNOWN;
private WifiInfo mWifiInfo;
/* For sending events to connectivity service handler */
private Handler mCsHandler;
private Context mContext;
private BroadcastReceiver mWifiStateReceiver;
private WifiManager mWifiManager;
private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker();
public WifiStateTracker(int netType, String networkName) {
mNetworkInfo = new NetworkInfo(netType, 0, networkName, "");
mLinkProperties = new LinkProperties();
@@ -174,6 +177,7 @@ public class WifiStateTracker implements NetworkStateTracker {
/**
* Fetch NetworkInfo for the network
*/
@Override
public NetworkInfo getNetworkInfo() {
return new NetworkInfo(mNetworkInfo);
}
@@ -181,6 +185,7 @@ public class WifiStateTracker implements NetworkStateTracker {
/**
* Fetch LinkProperties for the network
*/
@Override
public LinkProperties getLinkProperties() {
return new LinkProperties(mLinkProperties);
}
@@ -191,10 +196,47 @@ public class WifiStateTracker implements NetworkStateTracker {
*
* @return a copy of this connections capabilities, may be empty but never null.
*/
@Override
public LinkCapabilities getLinkCapabilities() {
return new LinkCapabilities(mLinkCapabilities);
}
/**
* Return link info
* @return an object of type WifiLinkInfo
*/
@Override
public LinkInfo getLinkInfo() {
if (mNetworkInfo == null) {
// no data available yet; just return
return null;
}
WifiLinkInfo li = new WifiLinkInfo();
li.mNetworkType = mNetworkInfo.getType();
synchronized(mSamplingDataTracker.mSamplingDataLock) {
mSamplingDataTracker.setCommonLinkInfoFields(li);
li.mTxGood = mSamplingDataTracker.getSampledTxPacketCount();
li.mTxBad = mSamplingDataTracker.getSampledTxPacketErrorCount();
}
// li.setTheoreticalRxBandwidth(??);
// li.setTheoreticalTxBandwidth(??);
if (mWifiInfo != null) {
li.mBssid = mWifiInfo.getBSSID();
int rssi = mWifiInfo.getRssi();
li.mRssi = rssi;
li.mNormalizedSignalStrength = mWifiManager.calculateSignalLevel(rssi,
LinkInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE);
}
return li;
}
/**
* Check if default route is set
*/
@@ -224,6 +266,7 @@ public class WifiStateTracker implements NetworkStateTracker {
if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
WifiManager.EXTRA_NETWORK_INFO);
mLinkProperties = intent.getParcelableExtra(
WifiManager.EXTRA_LINK_PROPERTIES);
if (mLinkProperties == null) {
@@ -234,7 +277,9 @@ public class WifiStateTracker implements NetworkStateTracker {
if (mLinkCapabilities == null) {
mLinkCapabilities = new LinkCapabilities();
}
// don't want to send redundent state messages
mWifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
// don't want to send redundant state messages
// but send portal check detailed state notice
NetworkInfo.State state = mNetworkInfo.getState();
if (mLastState == state &&
@@ -242,13 +287,15 @@ public class WifiStateTracker implements NetworkStateTracker {
return;
} else {
mLastState = state;
/* lets not sample traffic data across state changes */
mSamplingDataTracker.resetSamplingData();
}
Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
new NetworkInfo(mNetworkInfo));
msg.sendToTarget();
} else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) {
mLinkProperties = (LinkProperties) intent.getParcelableExtra(
WifiManager.EXTRA_LINK_PROPERTIES);
mLinkProperties = intent.getParcelableExtra(WifiManager.EXTRA_LINK_PROPERTIES);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
@@ -273,4 +320,15 @@ public class WifiStateTracker implements NetworkStateTracker {
public void supplyMessenger(Messenger messenger) {
// not supported on this network
}
@Override
public void startSampling(SamplingDataTracker.SamplingSnapshot s) {
mSamplingDataTracker.startSampling(s);
}
@Override
public void stopSampling(SamplingDataTracker.SamplingSnapshot s) {
mSamplingDataTracker.stopSampling(s);
}
}