Merge "Add blocking and retrying wrappers for INetd uses."
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user