summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2014-05-20 16:58:34 -0700
committerLorenzo Colitti <lorenzo@google.com>2014-05-21 19:53:04 -0700
commit20c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0 (patch)
treeec9404a13ea29b089f98eaa45e366a2a9f98c9b0
parente7a7ef99f94206a42388b5bf42a4c0e9f61a718e (diff)
downloadethernet-20c1c99c4351abd8bb3d6e8f966fcf3b6de0e5b0.tar.gz
Initial EthernetService implementation.
Bug: 14981801 Bug: 14993642 Change-Id: If392ef7063e096854ef830f4fe3b038439a1d307
-rw-r--r--Android.mk30
-rw-r--r--java/com/android/server/ethernet/EthernetConfigStore.java63
-rw-r--r--java/com/android/server/ethernet/EthernetNetworkFactory.java398
-rw-r--r--java/com/android/server/ethernet/EthernetService.java45
-rw-r--r--java/com/android/server/ethernet/EthernetServiceImpl.java177
5 files changed, 713 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..99559ac
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2014 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# Build the java code
+# ============================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/java
+LOCAL_SRC_FILES := $(call all-java-files-under, java) \
+ $(call all-Iaidl-files-under, java) \
+ $(call all-logtags-files-under, java)
+
+LOCAL_JAVA_LIBRARIES := services
+LOCAL_MODULE := ethernet-service
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/java/com/android/server/ethernet/EthernetConfigStore.java b/java/com/android/server/ethernet/EthernetConfigStore.java
new file mode 100644
index 0000000..7a428a8
--- /dev/null
+++ b/java/com/android/server/ethernet/EthernetConfigStore.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 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 com.android.server.ethernet;
+
+import android.net.IpConfiguration;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.LinkProperties;
+import android.os.Environment;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.server.net.IpConfigStore;
+
+
+/**
+ * This class provides an API to store and manage Ethernet network configuration.
+ */
+public class EthernetConfigStore extends IpConfigStore {
+ private static final String TAG = "EthernetConfigStore";
+
+ private static final String ipConfigFile = Environment.getDataDirectory() +
+ "/misc/ethernet/ipconfig.txt";
+
+ public EthernetConfigStore() {
+ }
+
+ public IpConfiguration readIpAndProxyConfigurations() {
+ SparseArray<IpConfiguration> networks = readIpAndProxyConfigurations(ipConfigFile);
+
+ if (networks.size() == 0) {
+ Log.w(TAG, "No Ethernet configuration found. Using default.");
+ return new IpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, new LinkProperties());
+ }
+
+ if (networks.size() > 1) {
+ // Currently we only support a single Ethernet interface.
+ Log.w(TAG, "Multiple Ethernet configurations detected. Only reading first one.");
+ }
+
+ return networks.valueAt(0);
+ }
+
+ public void writeIpAndProxyConfigurations(IpConfiguration config) {
+ SparseArray<IpConfiguration> networks = new SparseArray<IpConfiguration>();
+ networks.put(0, config);
+ writeIpAndProxyConfigurations(ipConfigFile, networks);
+ }
+}
diff --git a/java/com/android/server/ethernet/EthernetNetworkFactory.java b/java/com/android/server/ethernet/EthernetNetworkFactory.java
new file mode 100644
index 0000000..588913b
--- /dev/null
+++ b/java/com/android/server/ethernet/EthernetNetworkFactory.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2014 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 com.android.server.ethernet;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol;
+import android.net.DhcpResults;
+import android.net.InterfaceConfiguration;
+import android.net.NetworkUtils;
+import android.net.IpConfiguration;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkAgent;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkRequest;
+import android.net.EthernetManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.server.net.BaseNetworkObserver;
+
+import java.net.Inet4Address;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+class NetworkFactory extends Handler {
+ public interface Callback {
+ public void onRequestNetwork(NetworkRequest request, int currentScore);
+ public void onCancelRequest(NetworkRequest request);
+ }
+
+ private String mName;
+ private Callback mCallback;
+ private ConnectivityManager mCM;
+
+ NetworkFactory(String name, Context context, Looper looper, Callback callback) {
+ super(looper);
+ mCallback = callback;
+ mName = name;
+ mCM = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
+ public void register() {
+ logi("Registering network factory");
+ mCM.registerNetworkFactory(new Messenger(this), mName);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch(message.what) {
+ case NetworkFactoryProtocol.CMD_REQUEST_NETWORK:
+ mCallback.onRequestNetwork((NetworkRequest) message.obj, message.arg1);
+ break;
+ case NetworkFactoryProtocol.CMD_CANCEL_REQUEST:
+ mCallback.onCancelRequest((NetworkRequest) message.obj);
+ break;
+ default:
+ loge("Unhandled message " + message.what);
+ }
+ }
+
+ private void logi(String s) {
+ Log.i("NetworkFactory" + mName, s);
+ }
+
+ private void loge(String s) {
+ Log.e("NetworkFactory" + mName, s);
+ }
+}
+
+/**
+ * This class tracks the data connection associated with Ethernet.
+ * @hide
+ */
+class EthernetNetworkFactory implements NetworkFactory.Callback {
+ private static final String NETWORK_TYPE = "ETHERNET";
+ private static final String TAG = "EthernetNetworkFactory";
+ private static final int NETWORK_SCORE = 70;
+ private static final boolean DBG = true;
+
+ /** Tracks interface changes. Called from the NetworkManagementService thread. */
+ private InterfaceObserver mInterfaceObserver;
+
+ /** For static IP configuration */
+ private EthernetManager mEthernetManager;
+
+ /** To set link state and configure IP addresses. */
+ private INetworkManagementService mNMService;
+
+ /* To communicate with ConnectivityManager */
+ private NetworkCapabilities mNetworkCapabilities;
+ private NetworkAgent mNetworkAgent;
+ private NetworkFactory mFactory;
+
+ /** Product-dependent regular expression of interface names we want to track. */
+ private static String mIfaceMatch = "";
+
+ /** Data members. All accesses must be synchronized(this). */
+ private static String mIface = "";
+ private String mHwAddr;
+ private static boolean mLinkUp;
+ private NetworkInfo mNetworkInfo;
+ private LinkProperties mLinkProperties;
+
+ EthernetNetworkFactory() {
+ mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
+ mLinkProperties = new LinkProperties();
+ initNetworkCapabilities();
+ }
+
+ private void updateInterfaceState(String iface, boolean up) {
+ if (!mIface.equals(iface)) {
+ // We only support one interface.
+ return;
+ }
+ Log.d(TAG, "updateInterface: " + iface + " link " + (up ? "up" : "down"));
+
+ synchronized(this) {
+ mLinkUp = up;
+ mNetworkInfo.setIsAvailable(up);
+ DetailedState state = up ? DetailedState.CONNECTED: DetailedState.DISCONNECTED;
+ mNetworkInfo.setDetailedState(state, null, mHwAddr);
+ mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);
+ updateAgent();
+ }
+ }
+
+ private class InterfaceObserver extends BaseNetworkObserver {
+ @Override
+ public void interfaceLinkStateChanged(String iface, boolean up) {
+ updateInterfaceState(iface, up);
+ }
+
+ @Override
+ public void interfaceAdded(String iface) {
+ maybeTrackInterface(iface);
+ }
+
+ @Override
+ public void interfaceRemoved(String iface) {
+ stopTrackingInterface(iface);
+ }
+ }
+
+ private void setInterfaceUp(String iface) {
+ // Bring up the interface so we get link status indications.
+ try {
+ mNMService.setInterfaceUp(iface);
+ String hwAddr = null;
+ InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
+
+ if (config == null) {
+ Log.e(TAG, "Null iterface config for " + iface + ". Bailing out.");
+ return;
+ }
+
+ synchronized (this) {
+ if (mIface.isEmpty()) {
+ mIface = iface;
+ mHwAddr = config.getHardwareAddress();
+ mNetworkInfo.setIsAvailable(true);
+ mNetworkInfo.setExtraInfo(mHwAddr);
+ } else {
+ Log.e(TAG, "Interface unexpectedly changed from " + iface + " to " + mIface);
+ mNMService.setInterfaceDown(iface);
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error upping interface " + mIface + ": " + e);
+ }
+ }
+
+ private boolean maybeTrackInterface(String iface) {
+ // If we don't already have an interface, and if this interface matches
+ // our regex, start tracking it.
+ if (!iface.matches(mIfaceMatch) || !mIface.isEmpty())
+ return false;
+
+ Log.d(TAG, "Started tracking interface " + iface);
+ setInterfaceUp(iface);
+ return true;
+ }
+
+ private void stopTrackingInterface(String iface) {
+ if (!iface.equals(mIface))
+ return;
+
+ Log.d(TAG, "Stopped tracking interface " + iface);
+ disconnect();
+ synchronized (this) {
+ mIface = "";
+ mHwAddr = null;
+ mNetworkInfo.setExtraInfo(null);
+ }
+ }
+
+ private void setStaticIpAddress(LinkProperties linkProperties) {
+ Log.i(TAG, "Applying static IPv4 configuration to " + mIface + ": " + mLinkProperties);
+ try {
+ InterfaceConfiguration config = mNMService.getInterfaceConfig(mIface);
+ for (LinkAddress address: linkProperties.getLinkAddresses()) {
+ // IPv6 uses autoconfiguration.
+ if (address.getAddress() instanceof Inet4Address) {
+ config.setLinkAddress(address);
+ // This API only supports one IPv4 address.
+ mNMService.setInterfaceConfig(mIface, config);
+ break;
+ }
+ }
+ } catch(RemoteException e) {
+ Log.e(TAG, "Setting static IP address failed: " + e.getMessage());
+ } catch(IllegalStateException e) {
+ Log.e(TAG, "Setting static IP address failed: " + e.getMessage());
+ }
+ }
+
+ public void updateAgent() {
+ if (DBG) {
+ Log.i(TAG, "Updating mNetworkAgent with: " +
+ mNetworkCapabilities + ", " +
+ mNetworkInfo + ", " +
+ mLinkProperties);
+ }
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ mNetworkAgent.sendLinkProperties(mLinkProperties);
+ }
+
+ /* Called by the NetworkAgent on the handler thread. */
+ public void connect() {
+ // TODO: Handle DHCP renew.
+ Thread dhcpThread = new Thread(new Runnable() {
+ public void run() {
+ if (DBG) Log.i(TAG, "dhcpThread: mNetworkInfo=" + mNetworkInfo);
+ mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr);
+ LinkProperties linkProperties;
+
+ IpConfiguration config = mEthernetManager.getConfiguration();
+
+ if (config.ipAssignment == IpAssignment.STATIC) {
+ linkProperties = config.linkProperties;
+ linkProperties.setInterfaceName(mIface);
+ setStaticIpAddress(linkProperties);
+ } else {
+ DhcpResults dhcpResults = new DhcpResults();
+ // TODO: support more than one DHCP client.
+ if (!NetworkUtils.runDhcp(mIface, dhcpResults)) {
+ Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
+ mNetworkAgent.sendNetworkScore(0);
+ return;
+ }
+ linkProperties = dhcpResults.linkProperties;
+ }
+ if (config.proxySettings == ProxySettings.STATIC) {
+ linkProperties.setHttpProxy(config.linkProperties.getHttpProxy());
+ }
+
+ synchronized(EthernetNetworkFactory.this) {
+ mLinkProperties = linkProperties;
+ mNetworkInfo.setIsAvailable(true);
+ mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
+ updateAgent();
+ }
+ }
+ });
+ dhcpThread.start();
+ }
+
+ public void disconnect() {
+ NetworkUtils.stopDhcp(mIface);
+
+ synchronized(this) {
+ mLinkProperties.clear();
+ mNetworkInfo.setIsAvailable(false);
+ mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
+ updateAgent();
+ }
+
+ try {
+ mNMService.clearInterfaceAddresses(mIface);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to clear addresses or disable ipv6" + e);
+ }
+ }
+
+ /**
+ * Begin monitoring connectivity
+ */
+ public synchronized void start(Context context, Handler target) {
+ // The services we use.
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ mNMService = INetworkManagementService.Stub.asInterface(b);
+ mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE);
+
+ // Interface match regex.
+ mIfaceMatch = context.getResources().getString(
+ com.android.internal.R.string.config_ethernet_iface_regex);
+
+ // Create our NetworkAgent.
+ mNetworkAgent = new NetworkAgent(target.getLooper(), context, NETWORK_TYPE) {
+ public synchronized void sendNetworkScore(int score) {
+ Log.i(TAG, "sendNetworkScore(" + score + ")");
+ super.sendNetworkScore(score);
+ }
+ public void connect() {
+ EthernetNetworkFactory.this.connect();
+ };
+ public void disconnect() {
+ EthernetNetworkFactory.this.disconnect();
+ };
+ };
+ mNetworkAgent.sendNetworkScore(0);
+
+ // Create and register our NetworkFactory.
+ mFactory = new NetworkFactory(NETWORK_TYPE, context, target.getLooper(), this);
+ mFactory.register();
+
+ // Start tracking interface change events.
+ mInterfaceObserver = new InterfaceObserver();
+ try {
+ mNMService.registerObserver(mInterfaceObserver);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not register InterfaceObserver " + e);
+ }
+
+ // If an Ethernet interface is already connected, start tracking that.
+ // Otherwise, the first Ethernet interface to appear will be tracked.
+ try {
+ final String[] ifaces = mNMService.listInterfaces();
+ for (String iface : ifaces) {
+ if (maybeTrackInterface(iface)) {
+ break;
+ }
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not get list of interfaces " + e);
+ }
+ }
+
+ public synchronized void stop() {
+ disconnect();
+ mIface = "";
+ mHwAddr = null;
+ mLinkUp = false;
+ mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORK_TYPE, "");
+ mLinkProperties = new LinkProperties();
+ }
+
+ public void onRequestNetwork(NetworkRequest request, int currentScore) {
+ Log.i(TAG, "onRequestNetwork: (" + currentScore + "): " + request);
+ // TODO check that the transport is compatible.
+ mNetworkAgent.addNetworkRequest(request, currentScore);
+ }
+
+ public void onCancelRequest(NetworkRequest request) {
+ Log.i(TAG, "onCancelRequest: " + request);
+ mNetworkAgent.removeNetworkRequest(request);
+ }
+
+ private void initNetworkCapabilities() {
+ mNetworkCapabilities = new NetworkCapabilities();
+ mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET);
+ mNetworkCapabilities.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ mNetworkCapabilities.addNetworkCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ // We have no useful data on bandwidth. Say 100M up and 100M down. :-(
+ mNetworkCapabilities.setLinkUpstreamBandwidthKbps(100 * 1000);
+ mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100 * 1000);
+ }
+}
diff --git a/java/com/android/server/ethernet/EthernetService.java b/java/com/android/server/ethernet/EthernetService.java
new file mode 100644
index 0000000..2448146
--- /dev/null
+++ b/java/com/android/server/ethernet/EthernetService.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 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 com.android.server.ethernet;
+
+import android.content.Context;
+import android.util.Log;
+import com.android.server.SystemService;
+
+public final class EthernetService extends SystemService {
+
+ private static final String TAG = "EthernetService";
+ final EthernetServiceImpl mImpl;
+
+ public EthernetService(Context context) {
+ super(context);
+ mImpl = new EthernetServiceImpl(context);
+ }
+
+ @Override
+ public void onStart() {
+ Log.i(TAG, "Registering service " + Context.ETHERNET_SERVICE);
+ publishBinderService(Context.ETHERNET_SERVICE, mImpl);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+ mImpl.start();
+ }
+ }
+}
diff --git a/java/com/android/server/ethernet/EthernetServiceImpl.java b/java/com/android/server/ethernet/EthernetServiceImpl.java
new file mode 100644
index 0000000..08a2e9a
--- /dev/null
+++ b/java/com/android/server/ethernet/EthernetServiceImpl.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2014 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 com.android.server.ethernet;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import com.android.internal.util.IndentingPrintWriter;
+import android.net.ConnectivityManager;
+import android.net.IEthernetManager;
+import android.net.IpConfiguration;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.NetworkAgent;
+import android.net.NetworkInfo;
+import android.net.NetworkRequest;
+import android.net.RouteInfo;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.PrintWriterPrinter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+
+/**
+ * EthernetServiceImpl handles remote Ethernet operation requests by implementing
+ * the IEthernetManager interface.
+ *
+ * @hide
+ */
+public class EthernetServiceImpl extends IEthernetManager.Stub {
+ private static final String TAG = "EthernetServiceImpl";
+
+ private final Context mContext;
+ private final EthernetConfigStore mEthernetConfigStore;
+ private final INetworkManagementService mNMService;
+ private final AtomicBoolean mStarted = new AtomicBoolean(false);
+ private IpConfiguration mIpConfiguration;
+ private ConnectivityManager mCM;
+
+ private Handler mHandler;
+ private NetworkInfo mNetworkInfo;
+ private EthernetNetworkFactory mTracker;
+
+ public EthernetServiceImpl(Context context) {
+ mContext = context;
+ Log.i(TAG, "Creating EthernetConfigStore");
+ mEthernetConfigStore = new EthernetConfigStore();
+ mIpConfiguration = mEthernetConfigStore.readIpAndProxyConfigurations();
+
+ Log.i(TAG, "Read stored IP configuration: " + mIpConfiguration);
+
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ mNMService = INetworkManagementService.Stub.asInterface(b);
+
+ mTracker = new EthernetNetworkFactory();
+ }
+
+ private void enforceAccessPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NETWORK_STATE,
+ "EthernetService");
+ }
+
+ private void enforceChangePermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE,
+ "EthernetService");
+ }
+
+ private void enforceConnectivityInternalPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ "ConnectivityService");
+ }
+
+ public void start() {
+ Log.i(TAG, "Starting Ethernet service");
+ mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ HandlerThread handlerThread = new HandlerThread("EthernetServiceThread");
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper());
+
+ mTracker.start(mContext, mHandler);
+
+ mStarted.set(true);
+ }
+
+ /**
+ * Get Ethernet configuration
+ * @return the Ethernet Configuration, contained in {@link IpConfiguration}.
+ */
+ public IpConfiguration getConfiguration() {
+ enforceAccessPermission();
+
+ synchronized (mIpConfiguration) {
+ return new IpConfiguration(mIpConfiguration);
+ }
+ }
+
+ /**
+ * Set Ethernet configuration
+ */
+ public void setConfiguration(IpConfiguration config) {
+ if (!mStarted.get()) {
+ Log.w(TAG, "System isn't ready enough to change ethernet configuration");
+ }
+
+ enforceChangePermission();
+ enforceConnectivityInternalPermission();
+
+ synchronized (mIpConfiguration) {
+ mEthernetConfigStore.writeIpAndProxyConfigurations(config);
+
+ // TODO: this does not check proxy settings, gateways, etc.
+ // Fix this by making IpConfiguration a complete representation of static configuration.
+ if (!config.equals(mIpConfiguration)) {
+ mIpConfiguration.ipAssignment = config.ipAssignment;
+ mIpConfiguration.proxySettings = config.proxySettings;
+ mIpConfiguration.linkProperties = new LinkProperties(config.linkProperties);
+
+ mTracker.stop();
+ mTracker.start(mContext, mHandler);
+ }
+ }
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump EthernetService from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+ pw.println("Stored Ethernet configuration: ");
+
+ pw.increaseIndent();
+ pw.println(mIpConfiguration);
+ pw.decreaseIndent();
+
+ pw.println("Handler:");
+ pw.increaseIndent();
+ mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl");
+ pw.decreaseIndent();
+ }
+}