Merge "Add blocking and retrying wrappers for INetd uses."

This commit is contained in:
Treehugger Robot
2017-03-16 02:42:15 +00:00
committed by Gerrit Code Review
2 changed files with 101 additions and 6 deletions

View File

@ -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;
}

View File

@ -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);
}
}
}
}