diff options
| -rw-r--r-- | services/net/java/android/net/ip/IpManager.java | 17 | ||||
| -rw-r--r-- | services/net/java/android/net/util/NetdService.java | 90 |
2 files changed, 101 insertions, 6 deletions
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java index a3b0429bb148..3e3a19b8effd 100644 --- a/services/net/java/android/net/ip/IpManager.java +++ b/services/net/java/android/net/ip/IpManager.java @@ -23,6 +23,7 @@ import android.content.Context; import android.net.apf.ApfCapabilities; import android.net.apf.ApfFilter; import android.net.DhcpResults; +import android.net.INetd; import android.net.InterfaceConfiguration; import android.net.LinkAddress; import android.net.LinkProperties; @@ -34,10 +35,12 @@ import android.net.dhcp.DhcpClient; import android.net.metrics.IpConnectivityLog; import android.net.metrics.IpManagerEvent; import android.net.util.MultinetworkPolicyTracker; +import android.net.util.NetdService; import android.os.INetworkManagementService; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.ServiceSpecificException; import android.os.SystemClock; import android.text.TextUtils; import android.util.LocalLog; @@ -1027,14 +1030,16 @@ public class IpManager extends StateMachine { private boolean startIPv6() { // Set privacy extensions. + final String PREFER_TEMPADDRS = "2"; try { - mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); + NetdService.run((INetd netd) -> { + netd.setProcSysNet( + INetd.IPV6, INetd.CONF, mInterfaceName, "use_tempaddr", + PREFER_TEMPADDRS); + }); mNwService.enableIpv6(mInterfaceName); - } catch (RemoteException re) { - logError("Unable to change interface settings: %s", re); - return false; - } catch (IllegalStateException ie) { - logError("Unable to change interface settings: %s", ie); + } catch (IllegalStateException|RemoteException|ServiceSpecificException e) { + logError("Unable to change interface settings: %s", e); return false; } diff --git a/services/net/java/android/net/util/NetdService.java b/services/net/java/android/net/util/NetdService.java index 153cb502afca..6e69ff56c723 100644 --- a/services/net/java/android/net/util/NetdService.java +++ b/services/net/java/android/net/util/NetdService.java @@ -17,7 +17,10 @@ package android.net.util; import android.net.INetd; +import android.os.RemoteException; import android.os.ServiceManager; +import android.os.ServiceSpecificException; +import android.os.SystemClock; import android.util.Log; @@ -27,15 +30,24 @@ import android.util.Log; public class NetdService { private static final String TAG = NetdService.class.getSimpleName(); private static final String NETD_SERVICE_NAME = "netd"; + private static final long BASE_TIMEOUT_MS = 100; + private static final long MAX_TIMEOUT_MS = 1000; + /** + * Return an INetd instance, or null if not available. + * * It is the caller's responsibility to check for a null return value * and to handle RemoteException errors from invocations on the returned * interface if, for example, netd dies and is restarted. * + * Returned instances of INetd should not be cached. + * * @return an INetd instance or null. */ public static INetd getInstance() { + // NOTE: ServiceManager does no caching for the netd service, + // because netd is not one of the defined common services. final INetd netdInstance = INetd.Stub.asInterface( ServiceManager.getService(NETD_SERVICE_NAME)); if (netdInstance == null) { @@ -43,4 +55,82 @@ public class NetdService { } return netdInstance; } + + /** + * Blocks for a specified time until an INetd instance is available. + * + * It is the caller's responsibility to handle RemoteException errors + * from invocations on the returned interface if, for example, netd + * dies after this interface was returned. + * + * Returned instances of INetd should not be cached. + * + * Special values of maxTimeoutMs include: 0, meaning try to obtain an + * INetd instance only once, and -1 (or any value less than 0), meaning + * try to obtain an INetd instance indefinitely. + * + * @param maxTimeoutMs the maximum time to spend getting an INetd instance + * @return an INetd instance or null if no instance is available + * within |maxTimeoutMs| milliseconds. + */ + public static INetd get(long maxTimeoutMs) { + if (maxTimeoutMs == 0) return getInstance(); + + final long stop = (maxTimeoutMs > 0) + ? SystemClock.elapsedRealtime() + maxTimeoutMs + : Long.MAX_VALUE; + + long timeoutMs = 0; + while (true) { + final INetd netdInstance = getInstance(); + if (netdInstance != null) { + return netdInstance; + } + + final long remaining = stop - SystemClock.elapsedRealtime(); + if (remaining <= 0) break; + + // No netdInstance was received; sleep and retry. + timeoutMs = Math.min(timeoutMs + BASE_TIMEOUT_MS, MAX_TIMEOUT_MS); + timeoutMs = Math.min(timeoutMs, remaining); + try { + Thread.sleep(timeoutMs); + } catch (InterruptedException e) {} + } + return null; + } + + /** + * Blocks until an INetd instance is available. + * + * It is the caller's responsibility to handle RemoteException errors + * from invocations on the returned interface if, for example, netd + * dies after this interface was returned. + * + * Returned instances of INetd should not be cached. + * + * @return an INetd instance. + */ + public static INetd get() { + return get(-1); + } + + public static interface NetdCommand { + void run(INetd netd) throws RemoteException; + } + + /** + * Blocks until an INetd instance is availabe, and retries until either + * the command succeeds or a runtime exception is thrown. + */ + public static void run(NetdCommand cmd) { + while (true) { + try { + cmd.run(get()); + return; + } catch (RemoteException re) { + Log.e(TAG, "error communicating with netd: " + re); + } + } + } } |