diff options
4 files changed, 122 insertions, 0 deletions
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl index dd9c39f..b7af374 100644 --- a/core/java/android/net/INetworkManagementEventObserver.aidl +++ b/core/java/android/net/INetworkManagementEventObserver.aidl @@ -17,6 +17,7 @@ package android.net; import android.net.LinkAddress; +import android.net.RouteInfo; /** * Callback class for receiving events from an INetworkManagementService @@ -98,4 +99,14 @@ interface INetworkManagementEventObserver { * @param servers The IP addresses of the DNS servers. */ void interfaceDnsServerInfo(String iface, long lifetime, in String[] servers); + + /** + * A route has been added or updated. + */ + void routeUpdated(in RouteInfo route); + + /** + * A route has been removed. + */ + void routeRemoved(in RouteInfo route); } diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java index 430dd63..3d9fb5c 100644 --- a/core/java/com/android/server/net/BaseNetworkObserver.java +++ b/core/java/com/android/server/net/BaseNetworkObserver.java @@ -18,6 +18,7 @@ package com.android.server.net; import android.net.INetworkManagementEventObserver; import android.net.LinkAddress; +import android.net.RouteInfo; /** * Base {@link INetworkManagementEventObserver} that provides no-op @@ -70,4 +71,14 @@ public class BaseNetworkObserver extends INetworkManagementEventObserver.Stub { public void interfaceDnsServerInfo(String iface, long lifetime, String[] servers) { // default no-op } + + @Override + public void routeUpdated(RouteInfo route) { + // default no-op + } + + @Override + public void routeRemoved(RouteInfo route) { + // default no-op + } } diff --git a/core/java/com/android/server/net/NetlinkTracker.java b/core/java/com/android/server/net/NetlinkTracker.java index 82df2e5..7dd8dd8 100644 --- a/core/java/com/android/server/net/NetlinkTracker.java +++ b/core/java/com/android/server/net/NetlinkTracker.java @@ -18,6 +18,7 @@ package com.android.server.net; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.RouteInfo; import android.util.Log; /** @@ -84,6 +85,12 @@ public class NetlinkTracker extends BaseNetworkObserver { } } + private void maybeLog(String operation, Object o) { + if (DBG) { + Log.d(TAG, operation + ": " + o.toString()); + } + } + @Override public void addressUpdated(String iface, LinkAddress address) { if (mInterfaceName.equals(iface)) { @@ -112,6 +119,34 @@ public class NetlinkTracker extends BaseNetworkObserver { } } + @Override + public void routeUpdated(RouteInfo route) { + if (mInterfaceName.equals(route.getInterface())) { + maybeLog("routeUpdated", route); + boolean changed; + synchronized (this) { + changed = mLinkProperties.addRoute(route); + } + if (changed) { + mCallback.update(); + } + } + } + + @Override + public void routeRemoved(RouteInfo route) { + if (mInterfaceName.equals(route.getInterface())) { + maybeLog("routeRemoved", route); + boolean changed; + synchronized (this) { + changed = mLinkProperties.removeRoute(route); + } + if (changed) { + mCallback.update(); + } + } + } + /** * Returns a copy of this object's LinkProperties. */ diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index d26f3fc..7022294 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -41,6 +41,7 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.InterfaceConfiguration; +import android.net.IpPrefix; import android.net.LinkAddress; import android.net.NetworkStats; import android.net.NetworkUtils; @@ -145,6 +146,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub public static final int InterfaceClassActivity = 613; public static final int InterfaceAddressChange = 614; public static final int InterfaceDnsServerInfo = 615; + public static final int RouteChange = 616; } static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1; @@ -580,6 +582,28 @@ public class NetworkManagementService extends INetworkManagementService.Stub } } + /** + * Notify our observers of a route change. + */ + private void notifyRouteChange(String action, RouteInfo route) { + final int length = mObservers.beginBroadcast(); + try { + for (int i = 0; i < length; i++) { + try { + if (action.equals("updated")) { + mObservers.getBroadcastItem(i).routeUpdated(route); + } else { + mObservers.getBroadcastItem(i).routeRemoved(route); + } + } catch (RemoteException e) { + } catch (RuntimeException e) { + } + } + } finally { + mObservers.finishBroadcast(); + } + } + // // Netd Callback handling // @@ -722,6 +746,47 @@ public class NetworkManagementService extends INetworkManagementService.Stub } return true; // break; + case NetdResponseCode.RouteChange: + /* + * A route has been updated or removed. + * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]" + */ + if (!cooked[1].equals("Route") || cooked.length < 6) { + throw new IllegalStateException(errorMessage); + } + + String via = null; + String dev = null; + boolean valid = true; + for (int i = 4; (i + 1) < cooked.length && valid; i += 2) { + if (cooked[i].equals("dev")) { + if (dev == null) { + dev = cooked[i+1]; + } else { + valid = false; // Duplicate interface. + } + } else if (cooked[i].equals("via")) { + if (via == null) { + via = cooked[i+1]; + } else { + valid = false; // Duplicate gateway. + } + } else { + valid = false; // Unknown syntax. + } + } + if (valid) { + try { + // InetAddress.parseNumericAddress(null) inexplicably returns ::1. + InetAddress gateway = null; + if (via != null) gateway = InetAddress.parseNumericAddress(via); + RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev); + notifyRouteChange(cooked[2], route); + return true; + } catch (IllegalArgumentException e) {} + } + throw new IllegalStateException(errorMessage); + // break; default: break; } return false; |