package android.bluetooth;
+import android.net.BaseNetworkStateTracker;
import android.os.IBinder;
import android.os.ServiceManager;
import android.os.INetworkManagementService;
*
* @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;
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);
mLinkCapabilities = new LinkCapabilities();
}
+ protected BaseNetworkStateTracker() {
+ // By default, let the sub classes construct everything
+ }
+
@Deprecated
protected Handler getTargetHandler() {
return mTarget;
}
@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
}
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
+ }
}
}
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;
+ }
+ }
}
*
* {@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;
* ConnectivityService.
* @hide
*/
-public class EthernetDataTracker implements NetworkStateTracker {
+public class EthernetDataTracker extends BaseNetworkStateTracker {
private static final String NETWORKTYPE = "ETHERNET";
private static final String TAG = "Ethernet";
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 = "";
package android.net;
+import android.net.LinkInfo;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkQuotaInfo;
String getMobileProvisioningUrl();
String getMobileRedirectedProvisioningUrl();
+
+ LinkInfo getLinkInfo(int networkType);
+
+ LinkInfo getActiveLinkInfo();
+
+ LinkInfo[] getAllLinkInfo();
+
}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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();
+ }
+
+}
package android.net;
parcelable LinkProperties;
-
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;
*
* {@hide}
*/
-public class MobileDataStateTracker implements NetworkStateTracker {
+public class MobileDataStateTracker extends BaseNetworkStateTracker {
private static final String TAG = "MobileDataStateTracker";
private static final boolean DBG = true;
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;
private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false);
+ private SignalStrength mSignalStrength;
+
+ private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker();
+
/**
* Create a new MobileDataStateTracker
* @param netType the ConnectivityManager network type
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;
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)) {
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 {
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,
}
}
+
/**
* @see android.net.NetworkStateTracker#getLinkProperties()
*/
+ @Override
public LinkProperties getLinkProperties() {
return new LinkProperties(mLinkProperties);
}
/**
* @see android.net.NetworkStateTracker#getLinkCapabilities()
*/
+ @Override
public LinkCapabilities getLinkCapabilities() {
return new LinkCapabilities(mLinkCapabilities);
}
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);
+ }
}
--- /dev/null
+/*
+ * 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;
+ }
+}
*/
public static final int EVENT_NETWORK_DISCONNECTED = BASE_NETWORK_STATE_TRACKER + 5;
-
/**
* -------------------------------------------------------------
* Control Interface
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.
*/
* 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);
+
}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+}
+
--- /dev/null
+/*
+ * 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;
+ }
+}
*/
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.
<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" />
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;
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;
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;
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;
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;
*/
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. */
List mProtectedNetworks;
private DataConnectionStats mDataConnectionStats;
+
private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0);
TelephonyManager mTelephonyManager;
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);
}
// 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;
// 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;
}
- /**
+ /**
* 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);
}
}
- /**
+ /**
* 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
*
+ " != tag:" + tag);
}
}
+ case EVENT_SAMPLE_INTERVAL_ELAPSED:
+ handleNetworkSamplingTimeout();
+ break;
}
}
}
}
}
};
+
+ @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);
+ }
}
+
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;
*
* @hide
*/
-public class WifiStateTracker implements NetworkStateTracker {
+public class WifiStateTracker extends BaseNetworkStateTracker {
private static final String NETWORKTYPE = "WIFI";
private static final String TAG = "WifiStateTracker";
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();
/**
* Fetch NetworkInfo for the network
*/
+ @Override
public NetworkInfo getNetworkInfo() {
return new NetworkInfo(mNetworkInfo);
}
/**
* Fetch LinkProperties for the network
*/
+ @Override
public LinkProperties getLinkProperties() {
return new LinkProperties(mLinkProperties);
}
*
* @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
*/
public boolean isDefaultRouteSet() {
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) {
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 &&
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();
}
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);
+ }
}
+