blob: 968cc5651a05383fb62bba2dd18d86bb9fa66809 [file] [log] [blame]
package com.android.clockwork.connectivity;
import android.content.Context;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkRequest;
import android.os.Looper;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.util.IndentingPrintWriter;
import com.android.clockwork.common.DebugAssert;
import java.util.Locale;
/**
* A dummy NetworkFactory whose primary job is to monitor NetworkRequests as they come in
* and out of ConnectivityService, so that it may keep track of the count of requests based
* on different characteristics (i.e. unmetered network requests) and bounce that information
* to a registered listener.
*/
public class WearNetworkObserver extends NetworkFactory {
private static final String TAG = "WearNetworkObserver";
private static final String NETWORK_TYPE = "WEAR_NETWORK_OBSERVER";
// At its best performance, Bluetooth proxy provides 200kbps of bandwidth, so any request
// for a bandwidth higher than this is considered "high bandwidth".
private static final int HIGH_BANDWIDTH_KBPS = 200 * 1024;
public interface Listener {
void onUnmeteredRequestsChanged(int numUnmeteredRequests);
void onHighBandwidthRequestsChanged(int numHighBandwidthRequests);
void onWifiRequestsChanged(int numWifiRequests);
void onCellularRequestsChanged(int numCellularRequests);
}
private final SparseArray<NetworkRequest> mUnmeteredRequests = new SparseArray<>();
private final SparseArray<NetworkRequest> mHighBandwidthRequests = new SparseArray<>();
private final SparseArray<NetworkRequest> mWifiRequests = new SparseArray<>();
private final SparseArray<NetworkRequest> mCellularRequests = new SparseArray<>();
private final Listener mListener;
public WearNetworkObserver(final Context context, Listener listener) {
super(Looper.getMainLooper(), context, NETWORK_TYPE, null);
DebugAssert.isMainThread();
mListener = listener;
}
@Override
protected void handleAddRequest(NetworkRequest req, int score) {
DebugAssert.isMainThread();
verboseLog("WearNetworkObserver: handleAddRequest");
if (mUnmeteredRequests.get(req.requestId) == null
&& req.networkCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) {
mUnmeteredRequests.put(req.requestId, req);
mListener.onUnmeteredRequestsChanged(mUnmeteredRequests.size());
}
if (mHighBandwidthRequests.get(req.requestId) == null
&& (req.networkCapabilities.getLinkDownstreamBandwidthKbps()
> HIGH_BANDWIDTH_KBPS)) {
mHighBandwidthRequests.put(req.requestId, req);
mListener.onHighBandwidthRequestsChanged(mHighBandwidthRequests.size());
}
if (mWifiRequests.get(req.requestId) == null
&& req.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
mWifiRequests.put(req.requestId, req);
mListener.onWifiRequestsChanged(mWifiRequests.size());
}
if (mCellularRequests.get(req.requestId) == null
&& req.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
mCellularRequests.put(req.requestId, req);
mListener.onCellularRequestsChanged(mCellularRequests.size());
}
verboseLog(String.format(Locale.US,
"handleAddRequest - [unmetered %d // highband %d // wifi %d // cell %d ]",
mUnmeteredRequests.size(),
mHighBandwidthRequests.size(),
mWifiRequests.size(),
mCellularRequests.size()));
}
@Override
public void handleRemoveRequest(NetworkRequest req) {
DebugAssert.isMainThread();
verboseLog("WearNetworkObserver: handleRemoveRequest");
NetworkRequest unmeteredReq = mUnmeteredRequests.get(req.requestId);
if (unmeteredReq != null) {
mUnmeteredRequests.remove(req.requestId);
mListener.onUnmeteredRequestsChanged(mUnmeteredRequests.size());
}
NetworkRequest highBandwidthReq = mHighBandwidthRequests.get(req.requestId);
if (highBandwidthReq != null) {
mHighBandwidthRequests.remove(req.requestId);
mListener.onHighBandwidthRequestsChanged(mHighBandwidthRequests.size());
}
NetworkRequest wifiReq = mWifiRequests.get(req.requestId);
if (wifiReq != null) {
mWifiRequests.remove(req.requestId);
mListener.onWifiRequestsChanged(mWifiRequests.size());
}
NetworkRequest cellReq = mCellularRequests.get(req.requestId);
if (cellReq != null) {
mCellularRequests.remove(req.requestId);
mListener.onCellularRequestsChanged(mCellularRequests.size());
}
verboseLog(String.format(Locale.US,
"handleRemoveRequest - [unmetered %d // highband %d // wifi %d // cell %d ]",
mUnmeteredRequests.size(),
mHighBandwidthRequests.size(),
mWifiRequests.size(),
mCellularRequests.size()));
}
private void verboseLog(String msg) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, msg);
}
}
/**
* This method may dump memory-inconsistent values when called off the main thread.
* This is preferable to synchronizing every call to handleAddRequest/handleRemoveRequest.
*/
public void dump(IndentingPrintWriter ipw) {
ipw.println("======== WearNetworkObserver ========");
ipw.printPair("Outstanding unmetered network requests", mUnmeteredRequests.size());
ipw.println();
ipw.printPair("Outstanding high-bandwidth network requests", mHighBandwidthRequests.size());
ipw.println();
ipw.printPair("Outstanding wifi network requests", mWifiRequests.size());
ipw.println();
ipw.printPair("Outstanding cellular network requests", mCellularRequests.size());
ipw.println();
ipw.println("Unmetered requests: ");
ipw.increaseIndent();
for (int i = 0; i < mUnmeteredRequests.size(); i++) {
NetworkRequest req = mUnmeteredRequests.valueAt(i);
// extra null-guard in case the object was removed while we were iterating
if (req != null) {
ipw.print(req.toString());
}
}
ipw.decreaseIndent();
ipw.println();
ipw.println("High-bandwidth requests: ");
ipw.increaseIndent();
for (int i = 0; i < mHighBandwidthRequests.size(); i++) {
// extra null-guard in case the object was removed while we were iterating
NetworkRequest req = mHighBandwidthRequests.valueAt(i);
if (req != null) {
ipw.print(req.toString());
}
}
ipw.decreaseIndent();
ipw.println();
ipw.println("Wifi requests: ");
ipw.increaseIndent();
for (int i = 0; i < mWifiRequests.size(); i++) {
// extra null-guard in case the object was removed while we were iterating
NetworkRequest req = mWifiRequests.valueAt(i);
if (req != null) {
ipw.print(req.toString());
}
}
ipw.decreaseIndent();
ipw.println();
ipw.println("Cellular requests: ");
ipw.increaseIndent();
for (int i = 0; i < mCellularRequests.size(); i++) {
// extra null-guard in case the object was removed while we were iterating
NetworkRequest req = mCellularRequests.valueAt(i);
if (req != null) {
ipw.print(req.toString());
}
}
ipw.decreaseIndent();
}
}