am e2a6d3df: Merge "Introduce network link quality statistics" into klp-dev
* commit 'e2a6d3df1257c1c04b1a14777bb7ee65f634bdc3': Introduce network link quality statistics
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 = "";
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
19
core/java/android/net/LinkInfo.aidl
Normal file
19
core/java/android/net/LinkInfo.aidl
Normal 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;
|
||||
128
core/java/android/net/LinkInfo.java
Normal file
128
core/java/android/net/LinkInfo.java
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,4 +18,3 @@
|
||||
package android.net;
|
||||
|
||||
parcelable LinkProperties;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
89
core/java/android/net/MobileLinkInfo.java
Normal file
89
core/java/android/net/MobileLinkInfo.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
295
core/java/android/net/SamplingDataTracker.java
Normal file
295
core/java/android/net/SamplingDataTracker.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
75
core/java/android/net/WifiLinkInfo.java
Normal file
75
core/java/android/net/WifiLinkInfo.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user