Merge "Expand logging capabilities of Tethering subsystem"
am: 0373340b07
Change-Id: I1381b8457781dcfafe52371a5dc7628282cb8efc
This commit is contained in:
@@ -183,6 +183,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
implements PendingIntent.OnFinished {
|
||||
private static final String TAG = ConnectivityService.class.getSimpleName();
|
||||
|
||||
public static final String DIAG_ARG = "--diag";
|
||||
public static final String SHORT_ARG = "--short";
|
||||
|
||||
private static final boolean DBG = true;
|
||||
private static final boolean VDBG = false;
|
||||
|
||||
@@ -1961,7 +1964,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
return;
|
||||
}
|
||||
|
||||
if (argsContain(args, "--diag")) {
|
||||
if (argsContain(args, DIAG_ARG)) {
|
||||
dumpNetworkDiagnostics(pw);
|
||||
return;
|
||||
}
|
||||
@@ -2053,7 +2056,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
pw.println();
|
||||
dumpAvoidBadWifiSettings(pw);
|
||||
|
||||
if (argsContain(args, "--short") == false) {
|
||||
if (argsContain(args, SHORT_ARG) == false) {
|
||||
pw.println();
|
||||
synchronized (mValidationLogs) {
|
||||
pw.println("mValidationLogs (most recent first):");
|
||||
|
||||
@@ -20,6 +20,7 @@ import static android.hardware.usb.UsbManager.USB_CONNECTED;
|
||||
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
|
||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
|
||||
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
|
||||
import static com.android.server.ConnectivityService.SHORT_ARG;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
@@ -47,6 +48,7 @@ import android.net.NetworkRequest;
|
||||
import android.net.NetworkState;
|
||||
import android.net.NetworkUtils;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.util.SharedLog;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
@@ -62,7 +64,6 @@ import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.LocalLog;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
@@ -146,9 +147,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
}
|
||||
}
|
||||
|
||||
private final static int MAX_LOG_RECORDS = 500;
|
||||
|
||||
private final LocalLog mLocalLog = new LocalLog(MAX_LOG_RECORDS);
|
||||
private final SharedLog mLog = new SharedLog(TAG);
|
||||
|
||||
// used to synchronize public access to members
|
||||
private final Object mPublicSync;
|
||||
@@ -181,7 +180,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
INetworkStatsService statsService, INetworkPolicyManager policyManager,
|
||||
Looper looper, MockableSystemProperties systemProperties,
|
||||
TetheringDependencies deps) {
|
||||
mLocalLog.log("CONSTRUCTED");
|
||||
mLog.mark("constructed");
|
||||
mContext = context;
|
||||
mNMService = nmService;
|
||||
mStatsService = statsService;
|
||||
@@ -197,9 +196,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
mTetherMasterSM.start();
|
||||
|
||||
mOffloadController = new OffloadController(mTetherMasterSM.getHandler(),
|
||||
deps.getOffloadHardwareInterface());
|
||||
deps.getOffloadHardwareInterface(), mLog);
|
||||
mUpstreamNetworkMonitor = new UpstreamNetworkMonitor(
|
||||
mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
|
||||
mContext, mTetherMasterSM, TetherMasterSM.EVENT_UPSTREAM_CALLBACK, mLog);
|
||||
mForwardedDownstreams = new HashSet<>();
|
||||
mSimChange = new SimChangeListener(
|
||||
mContext, mTetherMasterSM.getHandler(), () -> reevaluateSimCardProvisioning());
|
||||
@@ -1131,7 +1130,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
addState(mSetDnsForwardersErrorState);
|
||||
|
||||
mNotifyList = new ArrayList<>();
|
||||
mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList);
|
||||
mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog);
|
||||
setInitialState(mInitialState);
|
||||
}
|
||||
|
||||
@@ -1178,7 +1177,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
try {
|
||||
mNMService.setIpForwardingEnabled(true);
|
||||
} catch (Exception e) {
|
||||
mLocalLog.log("ERROR " + e);
|
||||
mLog.e(e);
|
||||
transitionTo(mSetIpForwardingEnabledErrorState);
|
||||
return false;
|
||||
}
|
||||
@@ -1191,12 +1190,12 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
mNMService.stopTethering();
|
||||
mNMService.startTethering(cfg.dhcpRanges);
|
||||
} catch (Exception ee) {
|
||||
mLocalLog.log("ERROR " + ee);
|
||||
mLog.e(ee);
|
||||
transitionTo(mStartTetheringErrorState);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mLocalLog.log("SET master tether settings: ON");
|
||||
mLog.log("SET master tether settings: ON");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1204,19 +1203,19 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
try {
|
||||
mNMService.stopTethering();
|
||||
} catch (Exception e) {
|
||||
mLocalLog.log("ERROR " + e);
|
||||
mLog.e(e);
|
||||
transitionTo(mStopTetheringErrorState);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
mNMService.setIpForwardingEnabled(false);
|
||||
} catch (Exception e) {
|
||||
mLocalLog.log("ERROR " + e);
|
||||
mLog.e(e);
|
||||
transitionTo(mSetIpForwardingDisabledErrorState);
|
||||
return false;
|
||||
}
|
||||
transitionTo(mInitialState);
|
||||
mLocalLog.log("SET master tether settings: OFF");
|
||||
mLog.log("SET master tether settings: OFF");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1342,13 +1341,13 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
}
|
||||
try {
|
||||
mNMService.setDnsForwarders(network, dnsServers);
|
||||
mLocalLog.log(String.format(
|
||||
"SET DNS forwarders: network=%s dnsServers=[%s]",
|
||||
mLog.log(String.format(
|
||||
"SET DNS forwarders: network=%s dnsServers=%s",
|
||||
network, Arrays.toString(dnsServers)));
|
||||
} catch (Exception e) {
|
||||
// TODO: Investigate how this can fail and what exactly
|
||||
// happens if/when such failures occur.
|
||||
mLocalLog.log("ERROR setting DNS forwarders failed, " + e);
|
||||
mLog.e("setting DNS forwarders failed, " + e);
|
||||
transitionTo(mSetDnsForwardersErrorState);
|
||||
}
|
||||
}
|
||||
@@ -1710,12 +1709,23 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
|
||||
pw.println("Log:");
|
||||
pw.increaseIndent();
|
||||
mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
|
||||
if (argsContain(args, SHORT_ARG)) {
|
||||
pw.println("<log removed for brevity>");
|
||||
} else {
|
||||
mLog.dump(fd, pw, args);
|
||||
}
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.decreaseIndent();
|
||||
}
|
||||
|
||||
private static boolean argsContain(String[] args, String target) {
|
||||
for (String arg : args) {
|
||||
if (arg.equals(target)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who,
|
||||
int state, int error) {
|
||||
@@ -1729,8 +1739,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
}
|
||||
}
|
||||
|
||||
mLocalLog.log(String.format("OBSERVED iface=%s state=%s error=%s",
|
||||
iface, state, error));
|
||||
mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
|
||||
|
||||
try {
|
||||
// Notify that we're tethering (or not) this interface.
|
||||
@@ -1768,8 +1777,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
|
||||
private void trackNewTetherableInterface(String iface, int interfaceType) {
|
||||
TetherState tetherState;
|
||||
tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
|
||||
interfaceType, mNMService, mStatsService, this,
|
||||
new IPv6TetheringInterfaceServices(iface, mNMService)));
|
||||
interfaceType, mLog, mNMService, mStatsService, this,
|
||||
new IPv6TetheringInterfaceServices(iface, mNMService, mLog)));
|
||||
mTetherStates.put(iface, tetherState);
|
||||
tetherState.stateMachine.start();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkState;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.util.NetworkConstants;
|
||||
import android.net.util.SharedLog;
|
||||
import android.util.Log;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
@@ -64,6 +65,7 @@ public class IPv6TetheringCoordinator {
|
||||
}
|
||||
|
||||
private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
|
||||
private final SharedLog mLog;
|
||||
// NOTE: mActiveDownstreams is a list and not a hash data structure because
|
||||
// we keep active downstreams in arrival order. This is done so /64s can
|
||||
// be parceled out on a "first come, first served" basis and a /64 used by
|
||||
@@ -74,8 +76,10 @@ public class IPv6TetheringCoordinator {
|
||||
private short mNextSubnetId;
|
||||
private NetworkState mUpstreamNetworkState;
|
||||
|
||||
public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList) {
|
||||
public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList,
|
||||
SharedLog log) {
|
||||
mNotifyList = notifyList;
|
||||
mLog = log.forSubComponent(TAG);
|
||||
mActiveDownstreams = new LinkedList<>();
|
||||
mUniqueLocalPrefix = generateUniqueLocalPrefix();
|
||||
mNextSubnetId = 0;
|
||||
@@ -115,7 +119,7 @@ public class IPv6TetheringCoordinator {
|
||||
if (VDBG) {
|
||||
Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
|
||||
}
|
||||
if (!canTetherIPv6(ns)) {
|
||||
if (!canTetherIPv6(ns, mLog)) {
|
||||
stopIPv6TetheringOnAllInterfaces();
|
||||
setUpstreamNetworkState(null);
|
||||
return;
|
||||
@@ -150,9 +154,7 @@ public class IPv6TetheringCoordinator {
|
||||
null);
|
||||
}
|
||||
|
||||
if (DBG) {
|
||||
Log.d(TAG, "setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
|
||||
}
|
||||
mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
|
||||
}
|
||||
|
||||
private void updateIPv6TetheringInterfaces() {
|
||||
@@ -206,7 +208,7 @@ public class IPv6TetheringCoordinator {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean canTetherIPv6(NetworkState ns) {
|
||||
private static boolean canTetherIPv6(NetworkState ns, SharedLog sharedLog) {
|
||||
// Broadly speaking:
|
||||
//
|
||||
// [1] does the upstream have an IPv6 default route?
|
||||
@@ -260,13 +262,11 @@ public class IPv6TetheringCoordinator {
|
||||
|
||||
final boolean outcome = canTether && supportedConfiguration;
|
||||
|
||||
if (VDBG) {
|
||||
if (ns == null) {
|
||||
Log.d(TAG, "No available upstream.");
|
||||
} else {
|
||||
Log.d(TAG, String.format("IPv6 tethering is %s for upstream: %s",
|
||||
(outcome ? "available" : "not available"), toDebugString(ns)));
|
||||
}
|
||||
if (ns == null) {
|
||||
sharedLog.log("No available upstream.");
|
||||
} else {
|
||||
sharedLog.log(String.format("IPv6 tethering is %s for upstream: %s",
|
||||
(outcome ? "available" : "not available"), toDebugString(ns)));
|
||||
}
|
||||
|
||||
return outcome;
|
||||
|
||||
@@ -28,10 +28,10 @@ import android.net.RouteInfo;
|
||||
import android.net.ip.RouterAdvertisementDaemon;
|
||||
import android.net.ip.RouterAdvertisementDaemon.RaParams;
|
||||
import android.net.util.NetdService;
|
||||
import android.net.util.SharedLog;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.os.ServiceSpecificException;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
@@ -54,6 +54,7 @@ public class IPv6TetheringInterfaceServices {
|
||||
|
||||
private final String mIfName;
|
||||
private final INetworkManagementService mNMService;
|
||||
private final SharedLog mLog;
|
||||
|
||||
private NetworkInterface mNetworkInterface;
|
||||
private byte[] mHwAddr;
|
||||
@@ -61,9 +62,11 @@ public class IPv6TetheringInterfaceServices {
|
||||
private RouterAdvertisementDaemon mRaDaemon;
|
||||
private RaParams mLastRaParams;
|
||||
|
||||
public IPv6TetheringInterfaceServices(String ifname, INetworkManagementService nms) {
|
||||
public IPv6TetheringInterfaceServices(
|
||||
String ifname, INetworkManagementService nms, SharedLog log) {
|
||||
mIfName = ifname;
|
||||
mNMService = nms;
|
||||
mLog = log.forSubComponent(mIfName);
|
||||
}
|
||||
|
||||
public boolean start() {
|
||||
@@ -72,12 +75,12 @@ public class IPv6TetheringInterfaceServices {
|
||||
try {
|
||||
mNetworkInterface = NetworkInterface.getByName(mIfName);
|
||||
} catch (SocketException e) {
|
||||
Log.e(TAG, "Error looking up NetworkInterfaces for " + mIfName, e);
|
||||
mLog.e("Error looking up NetworkInterfaces: " + e);
|
||||
stop();
|
||||
return false;
|
||||
}
|
||||
if (mNetworkInterface == null) {
|
||||
Log.e(TAG, "Failed to find NetworkInterface for " + mIfName);
|
||||
mLog.e("Failed to find NetworkInterface");
|
||||
stop();
|
||||
return false;
|
||||
}
|
||||
@@ -85,7 +88,7 @@ public class IPv6TetheringInterfaceServices {
|
||||
try {
|
||||
mHwAddr = mNetworkInterface.getHardwareAddress();
|
||||
} catch (SocketException e) {
|
||||
Log.e(TAG, "Failed to find hardware address for " + mIfName, e);
|
||||
mLog.e("Failed to find hardware address: " + e);
|
||||
stop();
|
||||
return false;
|
||||
}
|
||||
@@ -161,11 +164,11 @@ public class IPv6TetheringInterfaceServices {
|
||||
try {
|
||||
final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved);
|
||||
if (removalFailures > 0) {
|
||||
Log.e(TAG, String.format("Failed to remove %d IPv6 routes from local table.",
|
||||
mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
|
||||
removalFailures));
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to remove IPv6 routes from local table: ", e);
|
||||
mLog.e("Failed to remove IPv6 routes from local table: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +198,7 @@ public class IPv6TetheringInterfaceServices {
|
||||
// error (EEXIST is silently ignored).
|
||||
mNMService.addInterfaceToLocalNetwork(mIfName, toBeAdded);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to add IPv6 routes to local table: ", e);
|
||||
mLog.e("Failed to add IPv6 routes to local table: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,7 +209,7 @@ public class IPv6TetheringInterfaceServices {
|
||||
final INetd netd = NetdService.getInstance();
|
||||
if (netd == null) {
|
||||
if (newDnses != null) newDnses.clear();
|
||||
Log.e(TAG, "No netd service instance available; not setting local IPv6 addresses");
|
||||
mLog.e("No netd service instance available; not setting local IPv6 addresses");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -217,7 +220,7 @@ public class IPv6TetheringInterfaceServices {
|
||||
try {
|
||||
netd.interfaceDelAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
|
||||
} catch (ServiceSpecificException | RemoteException e) {
|
||||
Log.e(TAG, "Failed to remove local dns IP: " + dnsString, e);
|
||||
mLog.e("Failed to remove local dns IP " + dnsString + ": " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,7 +237,7 @@ public class IPv6TetheringInterfaceServices {
|
||||
try {
|
||||
netd.interfaceAddAddress(mIfName, dnsString, RFC7421_PREFIX_LENGTH);
|
||||
} catch (ServiceSpecificException | RemoteException e) {
|
||||
Log.e(TAG, "Failed to add local dns IP: " + dnsString, e);
|
||||
mLog.e("Failed to add local dns IP " + dnsString + ": " + e);
|
||||
newDnses.remove(dns);
|
||||
}
|
||||
}
|
||||
@@ -243,7 +246,7 @@ public class IPv6TetheringInterfaceServices {
|
||||
try {
|
||||
netd.tetherApplyDnsInterfaces();
|
||||
} catch (ServiceSpecificException | RemoteException e) {
|
||||
Log.e(TAG, "Failed to update local DNS caching server");
|
||||
mLog.e("Failed to update local DNS caching server");
|
||||
if (newDnses != null) newDnses.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,7 @@ package com.android.server.connectivity.tethering;
|
||||
|
||||
import android.net.LinkProperties;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.net.util.SharedLog;
|
||||
|
||||
/**
|
||||
* A class to encapsulate the business logic of programming the tethering
|
||||
@@ -32,13 +31,15 @@ public class OffloadController {
|
||||
|
||||
private final Handler mHandler;
|
||||
private final OffloadHardwareInterface mHwInterface;
|
||||
private final SharedLog mLog;
|
||||
private boolean mConfigInitialized;
|
||||
private boolean mControlInitialized;
|
||||
private LinkProperties mUpstreamLinkProperties;
|
||||
|
||||
public OffloadController(Handler h, OffloadHardwareInterface hwi) {
|
||||
public OffloadController(Handler h, OffloadHardwareInterface hwi, SharedLog log) {
|
||||
mHandler = h;
|
||||
mHwInterface = hwi;
|
||||
mLog = log.forSubComponent(TAG);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
@@ -47,7 +48,7 @@ public class OffloadController {
|
||||
if (!mConfigInitialized) {
|
||||
mConfigInitialized = mHwInterface.initOffloadConfig();
|
||||
if (!mConfigInitialized) {
|
||||
Log.d(TAG, "tethering offload config not supported");
|
||||
mLog.i("tethering offload config not supported");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.net.InterfaceConfiguration;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.NetworkUtils;
|
||||
import android.net.util.SharedLog;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
@@ -82,6 +83,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
private final State mTetheredState;
|
||||
private final State mUnavailableState;
|
||||
|
||||
private final SharedLog mLog;
|
||||
private final INetworkManagementService mNMService;
|
||||
private final INetworkStatsService mStatsService;
|
||||
private final IControlsTethering mTetherController;
|
||||
@@ -93,10 +95,12 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
private int mLastError;
|
||||
private String mMyUpstreamIfaceName; // may change over time
|
||||
|
||||
public TetherInterfaceStateMachine(String ifaceName, Looper looper, int interfaceType,
|
||||
INetworkManagementService nMService, INetworkStatsService statsService,
|
||||
IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) {
|
||||
public TetherInterfaceStateMachine(
|
||||
String ifaceName, Looper looper, int interfaceType, SharedLog log,
|
||||
INetworkManagementService nMService, INetworkStatsService statsService,
|
||||
IControlsTethering tetherController, IPv6TetheringInterfaceServices ipv6Svc) {
|
||||
super(ifaceName, looper);
|
||||
mLog = log.forSubComponent(ifaceName);
|
||||
mNMService = nMService;
|
||||
mStatsService = statsService;
|
||||
mTetherController = tetherController;
|
||||
@@ -162,7 +166,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
mNMService.setInterfaceConfig(mIfaceName, ifcg);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error configuring interface " + mIfaceName, e);
|
||||
mLog.e("Error configuring interface " + e);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -203,7 +207,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
transitionTo(mTetheredState);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Invalid tethering interface serving state specified.");
|
||||
mLog.e("Invalid tethering interface serving state specified.");
|
||||
}
|
||||
break;
|
||||
case CMD_INTERFACE_DOWN:
|
||||
@@ -232,13 +236,13 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
try {
|
||||
mNMService.tetherInterface(mIfaceName);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error Tethering: " + e.toString());
|
||||
mLog.e("Error Tethering: " + e);
|
||||
mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mIPv6TetherSvc.start()) {
|
||||
Log.e(TAG, "Failed to start IPv6TetheringInterfaceServices");
|
||||
mLog.e("Failed to start IPv6TetheringInterfaceServices");
|
||||
// TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
|
||||
return;
|
||||
}
|
||||
@@ -255,7 +259,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
mNMService.untetherInterface(mIfaceName);
|
||||
} catch (Exception e) {
|
||||
mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
|
||||
Log.e(TAG, "Failed to untether interface: " + e.toString());
|
||||
mLog.e("Failed to untether interface: " + e);
|
||||
}
|
||||
|
||||
configureIfaceIp(false);
|
||||
@@ -316,7 +320,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
maybeLogMessage(this, message.what);
|
||||
switch (message.what) {
|
||||
case CMD_TETHER_REQUESTED:
|
||||
Log.e(TAG, "CMD_TETHER_REQUESTED while in local hotspot mode.");
|
||||
mLog.e("CMD_TETHER_REQUESTED while in local-only hotspot mode.");
|
||||
break;
|
||||
case CMD_TETHER_CONNECTION_CHANGED:
|
||||
// Ignored in local hotspot state.
|
||||
@@ -389,7 +393,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
boolean retValue = true;
|
||||
switch (message.what) {
|
||||
case CMD_TETHER_REQUESTED:
|
||||
Log.e(TAG, "CMD_TETHER_REQUESTED while already tethering.");
|
||||
mLog.e("CMD_TETHER_REQUESTED while already tethering.");
|
||||
break;
|
||||
case CMD_TETHER_CONNECTION_CHANGED:
|
||||
String newUpstreamIfaceName = (String)(message.obj);
|
||||
@@ -406,7 +410,7 @@ public class TetherInterfaceStateMachine extends StateMachine {
|
||||
mNMService.startInterfaceForwarding(mIfaceName,
|
||||
newUpstreamIfaceName);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception enabling Nat: " + e.toString());
|
||||
mLog.e("Exception enabling NAT: " + e);
|
||||
cleanupUpstreamInterface(newUpstreamIfaceName);
|
||||
mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
|
||||
transitionTo(mInitialState);
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.NetworkState;
|
||||
import android.net.util.SharedLog;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -73,6 +74,7 @@ public class UpstreamNetworkMonitor {
|
||||
private static final int CALLBACK_MOBILE_REQUEST = 3;
|
||||
|
||||
private final Context mContext;
|
||||
private final SharedLog mLog;
|
||||
private final StateMachine mTarget;
|
||||
private final Handler mHandler;
|
||||
private final int mWhat;
|
||||
@@ -84,16 +86,18 @@ public class UpstreamNetworkMonitor {
|
||||
private boolean mDunRequired;
|
||||
private Network mCurrentDefault;
|
||||
|
||||
public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
|
||||
public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what, SharedLog log) {
|
||||
mContext = ctx;
|
||||
mTarget = tgt;
|
||||
mHandler = mTarget.getHandler();
|
||||
mWhat = what;
|
||||
mLog = log.forSubComponent(TAG);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public UpstreamNetworkMonitor(StateMachine tgt, int what, ConnectivityManager cm) {
|
||||
this(null, tgt, what);
|
||||
public UpstreamNetworkMonitor(
|
||||
StateMachine tgt, int what, ConnectivityManager cm, SharedLog log) {
|
||||
this(null, tgt, what, log);
|
||||
mCM = cm;
|
||||
}
|
||||
|
||||
@@ -136,7 +140,7 @@ public class UpstreamNetworkMonitor {
|
||||
|
||||
public void registerMobileNetworkRequest() {
|
||||
if (mMobileNetworkCallback != null) {
|
||||
Log.e(TAG, "registerMobileNetworkRequest() already registered");
|
||||
mLog.e("registerMobileNetworkRequest() already registered");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,7 +160,7 @@ public class UpstreamNetworkMonitor {
|
||||
// TODO: Change the timeout from 0 (no onUnavailable callback) to some
|
||||
// moderate callback timeout. This might be useful for updating some UI.
|
||||
// Additionally, we log a message to aid in any subsequent debugging.
|
||||
Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
|
||||
mLog.i("requesting mobile upstream network: " + mobileUpstreamRequest);
|
||||
|
||||
cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
|
||||
}
|
||||
|
||||
132
services/net/java/android/net/util/SharedLog.java
Normal file
132
services/net/java/android/net/util/SharedLog.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.util;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.LocalLog;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
|
||||
/**
|
||||
* Class to centralize logging functionality for tethering.
|
||||
*
|
||||
* All access to class methods other than dump() must be on the same thread.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SharedLog {
|
||||
private final static int DEFAULT_MAX_RECORDS = 500;
|
||||
private final static String COMPONENT_DELIMITER = ".";
|
||||
|
||||
private enum Category {
|
||||
NONE,
|
||||
ERROR,
|
||||
MARK,
|
||||
WARN,
|
||||
};
|
||||
|
||||
private final LocalLog mLocalLog;
|
||||
// The tag to use for output to the system log. This is not output to the
|
||||
// LocalLog because that would be redundant.
|
||||
private final String mTag;
|
||||
// The component (or subcomponent) of a system that is sharing this log.
|
||||
// This can grow in depth if components call forSubComponent() to obtain
|
||||
// their SharedLog instance. The tag is not included in the component for
|
||||
// brevity.
|
||||
private final String mComponent;
|
||||
|
||||
public SharedLog(String tag) {
|
||||
this(DEFAULT_MAX_RECORDS, tag);
|
||||
}
|
||||
|
||||
public SharedLog(int maxRecords, String tag) {
|
||||
this(new LocalLog(maxRecords), tag, tag);
|
||||
}
|
||||
|
||||
private SharedLog(LocalLog localLog, String tag, String component) {
|
||||
mLocalLog = localLog;
|
||||
mTag = tag;
|
||||
mComponent = component;
|
||||
}
|
||||
|
||||
public SharedLog forSubComponent(String component) {
|
||||
if (!isRootLogInstance()) {
|
||||
component = mComponent + COMPONENT_DELIMITER + component;
|
||||
}
|
||||
return new SharedLog(mLocalLog, mTag, component);
|
||||
}
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
||||
mLocalLog.readOnlyLocalLog().dump(fd, writer, args);
|
||||
}
|
||||
|
||||
//////
|
||||
// Methods that both log an entry and emit it to the system log.
|
||||
//////
|
||||
|
||||
public void e(Exception e) {
|
||||
Log.e(mTag, record(Category.ERROR, e.toString()));
|
||||
}
|
||||
|
||||
public void e(String msg) {
|
||||
Log.e(mTag, record(Category.ERROR, msg));
|
||||
}
|
||||
|
||||
public void i(String msg) {
|
||||
Log.i(mTag, record(Category.NONE, msg));
|
||||
}
|
||||
|
||||
public void w(String msg) {
|
||||
Log.w(mTag, record(Category.WARN, msg));
|
||||
}
|
||||
|
||||
//////
|
||||
// Methods that only log an entry (and do NOT emit to the system log).
|
||||
//////
|
||||
|
||||
public void log(String msg) {
|
||||
record(Category.NONE, msg);
|
||||
}
|
||||
|
||||
public void mark(String msg) {
|
||||
record(Category.MARK, msg);
|
||||
}
|
||||
|
||||
private String record(Category category, String msg) {
|
||||
final String entry = logLine(category, msg);
|
||||
mLocalLog.log(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
private String logLine(Category category, String msg) {
|
||||
final StringJoiner sj = new StringJoiner(" ");
|
||||
if (!isRootLogInstance()) sj.add("[" + mComponent + "]");
|
||||
if (category != Category.NONE) sj.add(category.toString());
|
||||
return sj.add(msg).toString();
|
||||
}
|
||||
|
||||
// Check whether this SharedLog instance is nominally the top level in
|
||||
// a potential hierarchy of shared logs (the root of a tree),
|
||||
// or is a subcomponent within the hierarchy.
|
||||
private boolean isRootLogInstance() {
|
||||
return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag);
|
||||
}
|
||||
}
|
||||
94
tests/net/java/android/net/util/SharedLogTest.java
Normal file
94
tests/net/java/android/net/util/SharedLogTest.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Vector;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class SharedLogTest {
|
||||
private static final String TIMESTAMP_PATTERN =
|
||||
"^[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9].[0-9][0-9][0-9]";
|
||||
private static final String TIMESTAMP = "mm-dd HH:MM:SS.xxx";
|
||||
|
||||
@Test
|
||||
public void testBasicOperation() {
|
||||
final SharedLog logTop = new SharedLog("top");
|
||||
logTop.mark("first post!");
|
||||
|
||||
final SharedLog logLevel2a = logTop.forSubComponent("twoA");
|
||||
final SharedLog logLevel2b = logTop.forSubComponent("twoB");
|
||||
logLevel2b.e("2b or not 2b");
|
||||
logLevel2a.w("second post?");
|
||||
|
||||
final SharedLog logLevel3 = logLevel2a.forSubComponent("three");
|
||||
logTop.log("still logging");
|
||||
logLevel3.log("3 >> 2");
|
||||
logLevel2a.mark("ok: last post");
|
||||
|
||||
final String[] expected = {
|
||||
TIMESTAMP + " - MARK first post!",
|
||||
TIMESTAMP + " - [twoB] ERROR 2b or not 2b",
|
||||
TIMESTAMP + " - [twoA] WARN second post?",
|
||||
TIMESTAMP + " - still logging",
|
||||
TIMESTAMP + " - [twoA.three] 3 >> 2",
|
||||
TIMESTAMP + " - [twoA] MARK ok: last post",
|
||||
};
|
||||
// Verify the logs are all there and in the correct order.
|
||||
verifyLogLines(expected, logTop);
|
||||
|
||||
// In fact, because they all share the same underlying LocalLog,
|
||||
// every subcomponent SharedLog's dump() is identical.
|
||||
verifyLogLines(expected, logLevel2a);
|
||||
verifyLogLines(expected, logLevel2b);
|
||||
verifyLogLines(expected, logLevel3);
|
||||
}
|
||||
|
||||
private static void verifyLogLines(String[] expected, SharedLog log) {
|
||||
final ByteArrayOutputStream ostream = new ByteArrayOutputStream();
|
||||
final PrintWriter pw = new PrintWriter(ostream, true);
|
||||
log.dump(null, pw, null);
|
||||
|
||||
final String dumpOutput = ostream.toString();
|
||||
assertTrue(dumpOutput != null);
|
||||
assertTrue(!"".equals(dumpOutput));
|
||||
|
||||
final String[] lines = dumpOutput.split("\n");
|
||||
assertEquals(expected.length, lines.length);
|
||||
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
// Fix up the timestamps.
|
||||
lines[i] = lines[i].replaceAll(TIMESTAMP_PATTERN, TIMESTAMP);
|
||||
}
|
||||
|
||||
for (int i = 0; i < expected.length; i++) {
|
||||
assertEquals(expected[i], lines[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import static com.android.server.connectivity.tethering.IControlsTethering.STATE
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.INetworkStatsService;
|
||||
import android.net.InterfaceConfiguration;
|
||||
import android.net.util.SharedLog;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.os.RemoteException;
|
||||
import android.os.test.TestLooper;
|
||||
@@ -63,12 +64,14 @@ public class TetherInterfaceStateMachineTest {
|
||||
@Mock private IControlsTethering mTetherHelper;
|
||||
@Mock private InterfaceConfiguration mInterfaceConfiguration;
|
||||
@Mock private IPv6TetheringInterfaceServices mIPv6TetheringInterfaceServices;
|
||||
@Mock private SharedLog mSharedLog;
|
||||
|
||||
private final TestLooper mLooper = new TestLooper();
|
||||
private TetherInterfaceStateMachine mTestedSm;
|
||||
|
||||
private void initStateMachine(int interfaceType) throws Exception {
|
||||
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(), interfaceType,
|
||||
mTestedSm = new TetherInterfaceStateMachine(
|
||||
IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog,
|
||||
mNMService, mStatsService, mTetherHelper, mIPv6TetheringInterfaceServices);
|
||||
mTestedSm.start();
|
||||
// Starting the state machine always puts us in a consistent state and notifies
|
||||
@@ -90,12 +93,13 @@ public class TetherInterfaceStateMachineTest {
|
||||
|
||||
@Before public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startsOutAvailable() {
|
||||
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
|
||||
TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
|
||||
TETHERING_BLUETOOTH, mSharedLog, mNMService, mStatsService, mTetherHelper,
|
||||
mIPv6TetheringInterfaceServices);
|
||||
mTestedSm.start();
|
||||
mLooper.dispatchAll();
|
||||
|
||||
@@ -25,11 +25,13 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.anyString;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
@@ -40,6 +42,7 @@ import android.net.IConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.util.SharedLog;
|
||||
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
@@ -69,6 +72,7 @@ public class UpstreamNetworkMonitorTest {
|
||||
|
||||
@Mock private Context mContext;
|
||||
@Mock private IConnectivityManager mCS;
|
||||
@Mock private SharedLog mLog;
|
||||
|
||||
private TestStateMachine mSM;
|
||||
private TestConnectivityManager mCM;
|
||||
@@ -78,10 +82,12 @@ public class UpstreamNetworkMonitorTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
reset(mContext);
|
||||
reset(mCS);
|
||||
reset(mLog);
|
||||
when(mLog.forSubComponent(anyString())).thenReturn(mLog);
|
||||
|
||||
mCM = spy(new TestConnectivityManager(mContext, mCS));
|
||||
mSM = new TestStateMachine();
|
||||
mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
|
||||
mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM, mLog);
|
||||
}
|
||||
|
||||
@After public void tearDown() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user