120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti/* 220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * Copyright (C) 2014 The Android Open Source Project 320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * 420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * Licensed under the Apache License, Version 2.0 (the "License"); 520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * you may not use this file except in compliance with the License. 620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * You may obtain a copy of the License at 720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * 820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * http://www.apache.org/licenses/LICENSE-2.0 920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * 1020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * Unless required by applicable law or agreed to in writing, software 1120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * distributed under the License is distributed on an "AS IS" BASIS, 1220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * See the License for the specific language governing permissions and 1420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * limitations under the License. 1520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti */ 1620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 1720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittipackage com.android.server.ethernet; 1820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 1920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.content.Context; 2020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.content.pm.PackageManager; 2120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.net.IEthernetManager; 22a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kimimport android.net.IEthernetServiceListener; 2320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.net.IpConfiguration; 2420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.net.IpConfiguration.IpAssignment; 2520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.net.IpConfiguration.ProxySettings; 2620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.os.Binder; 2720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.os.Handler; 2820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.os.HandlerThread; 29a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kimimport android.os.RemoteCallbackList; 3020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.os.RemoteException; 3176502788598a85d24b9ae3e253016a9370c49a42Billy Lauimport android.provider.Settings; 3220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.util.Log; 3320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport android.util.PrintWriterPrinter; 3420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 35a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kimimport com.android.internal.util.IndentingPrintWriter; 36a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim 3720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport java.io.FileDescriptor; 3820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport java.io.PrintWriter; 3920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittiimport java.util.concurrent.atomic.AtomicBoolean; 4020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 4120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti/** 4220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * EthernetServiceImpl handles remote Ethernet operation requests by implementing 4320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * the IEthernetManager interface. 4420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * 4520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * @hide 4620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti */ 4720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colittipublic class EthernetServiceImpl extends IEthernetManager.Stub { 4820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti private static final String TAG = "EthernetServiceImpl"; 4920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 5020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti private final Context mContext; 5120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti private final EthernetConfigStore mEthernetConfigStore; 5220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti private final AtomicBoolean mStarted = new AtomicBoolean(false); 5320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti private IpConfiguration mIpConfiguration; 5420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 5520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti private Handler mHandler; 56aea43f5901e6591c390b83b10d3dd9b515a6442aLorenzo Colitti private final EthernetNetworkFactory mTracker; 57a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim private final RemoteCallbackList<IEthernetServiceListener> mListeners = 58a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim new RemoteCallbackList<IEthernetServiceListener>(); 5920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 6020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti public EthernetServiceImpl(Context context) { 6120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mContext = context; 6220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti Log.i(TAG, "Creating EthernetConfigStore"); 6320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mEthernetConfigStore = new EthernetConfigStore(); 6420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations(); 6520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 6620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration); 6720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 68a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim mTracker = new EthernetNetworkFactory(mListeners); 6920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 7020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 7120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti private void enforceAccessPermission() { 7220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mContext.enforceCallingOrSelfPermission( 7320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti android.Manifest.permission.ACCESS_NETWORK_STATE, 7420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti "EthernetService"); 7520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 7620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 7720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti private void enforceChangePermission() { 7876502788598a85d24b9ae3e253016a9370c49a42Billy Lau int uid = Binder.getCallingUid(); 7976502788598a85d24b9ae3e253016a9370c49a42Billy Lau Settings.checkAndNoteChangeNetworkStateOperation(mContext, uid, Settings 8076502788598a85d24b9ae3e253016a9370c49a42Billy Lau .getPackageNameForUid(mContext, uid), true); 8120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 8220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 8320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti private void enforceConnectivityInternalPermission() { 8420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mContext.enforceCallingOrSelfPermission( 8520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti android.Manifest.permission.CONNECTIVITY_INTERNAL, 8620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti "ConnectivityService"); 8720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 8820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 8920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti public void start() { 9020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti Log.i(TAG, "Starting Ethernet service"); 9120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 9220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti HandlerThread handlerThread = new HandlerThread("EthernetServiceThread"); 9320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti handlerThread.start(); 9420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mHandler = new Handler(handlerThread.getLooper()); 9520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 9620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mTracker.start(mContext, mHandler); 9720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 9820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mStarted.set(true); 9920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 10020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 10120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti /** 10220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * Get Ethernet configuration 10320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * @return the Ethernet Configuration, contained in {@link IpConfiguration}. 10420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti */ 105a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim @Override 10620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti public IpConfiguration getConfiguration() { 10720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti enforceAccessPermission(); 10820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 10920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti synchronized (mIpConfiguration) { 11020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti return new IpConfiguration(mIpConfiguration); 11120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 11220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 11320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 11420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti /** 11520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti * Set Ethernet configuration 11620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti */ 117a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim @Override 11820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti public void setConfiguration(IpConfiguration config) { 11920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti if (!mStarted.get()) { 12020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti Log.w(TAG, "System isn't ready enough to change ethernet configuration"); 12120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 12220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 12320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti enforceChangePermission(); 12420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti enforceConnectivityInternalPermission(); 12520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 12620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti synchronized (mIpConfiguration) { 12720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mEthernetConfigStore.writeIpAndProxyConfigurations(config); 12820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 12920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti // TODO: this does not check proxy settings, gateways, etc. 13020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti // Fix this by making IpConfiguration a complete representation of static configuration. 13120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti if (!config.equals(mIpConfiguration)) { 13241a372f13a7d19807d91e09f2e955b8a61f02d5cLorenzo Colitti mIpConfiguration = new IpConfiguration(config); 13320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mTracker.stop(); 13420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mTracker.start(mContext, mHandler); 13520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 13620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 13720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 138a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim 139a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim /** 140a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim * Indicates whether the system currently has one or more 141a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim * Ethernet interfaces. 142a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim */ 143a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim @Override 144a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim public boolean isAvailable() { 145a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim enforceAccessPermission(); 146a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim return mTracker.isTrackingInterface(); 147a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim } 148a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim 149a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim /** 150a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim * Addes a listener. 151a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim * @param listener A {@link IEthernetServiceListener} to add. 152a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim */ 153a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim public void addListener(IEthernetServiceListener listener) { 154a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim if (listener == null) { 155a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim throw new IllegalArgumentException("listener must not be null"); 156a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim } 157a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim enforceAccessPermission(); 158a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim mListeners.register(listener); 159a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim } 160a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim 161a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim /** 162a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim * Removes a listener. 163a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim * @param listener A {@link IEthernetServiceListener} to remove. 164a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim */ 165a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim public void removeListener(IEthernetServiceListener listener) { 166a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim if (listener == null) { 167a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim throw new IllegalArgumentException("listener must not be null"); 168a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim } 169a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim enforceAccessPermission(); 170a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim mListeners.unregister(listener); 171a3d7e61812f8d68ca109280c4e7589e4f968723aJaewan Kim } 17220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 17320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti @Override 17420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 17520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 17620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 17720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti != PackageManager.PERMISSION_GRANTED) { 17820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti pw.println("Permission Denial: can't dump EthernetService from pid=" 17920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti + Binder.getCallingPid() 18020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti + ", uid=" + Binder.getCallingUid()); 18120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti return; 18220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 18320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 184aea43f5901e6591c390b83b10d3dd9b515a6442aLorenzo Colitti pw.println("Current Ethernet state: "); 185aea43f5901e6591c390b83b10d3dd9b515a6442aLorenzo Colitti pw.increaseIndent(); 186aea43f5901e6591c390b83b10d3dd9b515a6442aLorenzo Colitti mTracker.dump(fd, pw, args); 187aea43f5901e6591c390b83b10d3dd9b515a6442aLorenzo Colitti pw.decreaseIndent(); 188aea43f5901e6591c390b83b10d3dd9b515a6442aLorenzo Colitti 189aea43f5901e6591c390b83b10d3dd9b515a6442aLorenzo Colitti pw.println(); 190aea43f5901e6591c390b83b10d3dd9b515a6442aLorenzo Colitti pw.println("Stored Ethernet configuration: "); 19120c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti pw.increaseIndent(); 19220c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti pw.println(mIpConfiguration); 19320c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti pw.decreaseIndent(); 19420c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti 19520c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti pw.println("Handler:"); 19620c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti pw.increaseIndent(); 19720c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl"); 19820c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti pw.decreaseIndent(); 19920c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti } 20020c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0Lorenzo Colitti} 201