Notify network observers of route changes.
Bug: 9180552
Change-Id: If8432bc74335676320b815784b21f404d3479c35
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 @@
* @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 @@
import android.net.INetworkManagementEventObserver;
import android.net.LinkAddress;
+import android.net.RouteInfo;
/**
* Base {@link INetworkManagementEventObserver} that provides no-op
@@ -70,4 +71,14 @@
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 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.RouteInfo;
import android.util.Log;
/**
@@ -84,6 +85,12 @@
}
}
+ 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 @@
}
}
+ @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.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 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 @@
}
}
+ /**
+ * 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 @@
}
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;