Only one entry is allowed to be added to route table 60 for all interface ipv6 link local addresses, so skip ipv6 link local addresses on all interfaces when enabling NAT Change-Id: Ibbe6c2bdae83586cdd38287089715f3433bbb91f Signed-off-by: jiaguo <jiaguo@marvell.com>
1823 lines
67 KiB
Java
1823 lines
67 KiB
Java
/*
|
|
* Copyright (C) 2007 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.server;
|
|
|
|
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
|
|
import static android.Manifest.permission.DUMP;
|
|
import static android.Manifest.permission.SHUTDOWN;
|
|
import static android.net.NetworkStats.SET_DEFAULT;
|
|
import static android.net.NetworkStats.TAG_NONE;
|
|
import static android.net.NetworkStats.UID_ALL;
|
|
import static android.net.TrafficStats.UID_TETHERING;
|
|
import static com.android.server.NetworkManagementService.NetdResponseCode.ClatdStatusResult;
|
|
import static com.android.server.NetworkManagementService.NetdResponseCode.GetMarkResult;
|
|
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceGetCfgResult;
|
|
import static com.android.server.NetworkManagementService.NetdResponseCode.InterfaceListResult;
|
|
import static com.android.server.NetworkManagementService.NetdResponseCode.IpFwdStatusResult;
|
|
import static com.android.server.NetworkManagementService.NetdResponseCode.TetherDnsFwdTgtListResult;
|
|
import static com.android.server.NetworkManagementService.NetdResponseCode.TetherInterfaceListResult;
|
|
import static com.android.server.NetworkManagementService.NetdResponseCode.TetherStatusResult;
|
|
import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
|
|
import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
|
|
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
|
|
|
|
import android.content.Context;
|
|
import android.net.INetworkManagementEventObserver;
|
|
import android.net.InterfaceConfiguration;
|
|
import android.net.LinkAddress;
|
|
import android.net.NetworkStats;
|
|
import android.net.NetworkUtils;
|
|
import android.net.RouteInfo;
|
|
import android.net.wifi.WifiConfiguration;
|
|
import android.net.wifi.WifiConfiguration.KeyMgmt;
|
|
import android.os.BatteryStats;
|
|
import android.os.Binder;
|
|
import android.os.Handler;
|
|
import android.os.INetworkManagementService;
|
|
import android.os.Process;
|
|
import android.os.RemoteCallbackList;
|
|
import android.os.RemoteException;
|
|
import android.os.ServiceManager;
|
|
import android.os.SystemClock;
|
|
import android.os.SystemProperties;
|
|
import android.util.Log;
|
|
import android.util.Slog;
|
|
import android.util.SparseBooleanArray;
|
|
|
|
import com.android.internal.app.IBatteryStats;
|
|
import com.android.internal.net.NetworkStatsFactory;
|
|
import com.android.internal.util.Preconditions;
|
|
import com.android.server.NativeDaemonConnector.Command;
|
|
import com.android.server.NativeDaemonConnector.SensitiveArg;
|
|
import com.android.server.net.LockdownVpnTracker;
|
|
import com.google.android.collect.Maps;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.DataInputStream;
|
|
import java.io.File;
|
|
import java.io.FileDescriptor;
|
|
import java.io.FileInputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.io.PrintWriter;
|
|
import java.net.Inet4Address;
|
|
import java.net.InetAddress;
|
|
import java.net.InterfaceAddress;
|
|
import java.net.NetworkInterface;
|
|
import java.net.SocketException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.StringTokenizer;
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public class NetworkManagementService extends INetworkManagementService.Stub
|
|
implements Watchdog.Monitor {
|
|
private static final String TAG = "NetworkManagementService";
|
|
private static final boolean DBG = false;
|
|
private static final String NETD_TAG = "NetdConnector";
|
|
private static final String NETD_SOCKET_NAME = "netd";
|
|
|
|
private static final String ADD = "add";
|
|
private static final String REMOVE = "remove";
|
|
|
|
private static final String ALLOW = "allow";
|
|
private static final String DENY = "deny";
|
|
|
|
private static final String DEFAULT = "default";
|
|
private static final String SECONDARY = "secondary";
|
|
|
|
/**
|
|
* Name representing {@link #setGlobalAlert(long)} limit when delivered to
|
|
* {@link INetworkManagementEventObserver#limitReached(String, String)}.
|
|
*/
|
|
public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
|
|
|
|
class NetdResponseCode {
|
|
/* Keep in sync with system/netd/ResponseCode.h */
|
|
public static final int InterfaceListResult = 110;
|
|
public static final int TetherInterfaceListResult = 111;
|
|
public static final int TetherDnsFwdTgtListResult = 112;
|
|
public static final int TtyListResult = 113;
|
|
public static final int TetheringStatsListResult = 114;
|
|
|
|
public static final int TetherStatusResult = 210;
|
|
public static final int IpFwdStatusResult = 211;
|
|
public static final int InterfaceGetCfgResult = 213;
|
|
public static final int SoftapStatusResult = 214;
|
|
public static final int InterfaceRxCounterResult = 216;
|
|
public static final int InterfaceTxCounterResult = 217;
|
|
public static final int QuotaCounterResult = 220;
|
|
public static final int TetheringStatsResult = 221;
|
|
public static final int DnsProxyQueryResult = 222;
|
|
public static final int ClatdStatusResult = 223;
|
|
public static final int GetMarkResult = 225;
|
|
|
|
public static final int InterfaceChange = 600;
|
|
public static final int BandwidthControl = 601;
|
|
public static final int InterfaceClassActivity = 613;
|
|
public static final int InterfaceAddressChange = 614;
|
|
public static final int InterfaceDnsServerInfo = 615;
|
|
}
|
|
|
|
/**
|
|
* Binder context for this service
|
|
*/
|
|
private Context mContext;
|
|
|
|
/**
|
|
* connector object for communicating with netd
|
|
*/
|
|
private NativeDaemonConnector mConnector;
|
|
|
|
private final Handler mMainHandler = new Handler();
|
|
|
|
private Thread mThread;
|
|
private CountDownLatch mConnectedSignal = new CountDownLatch(1);
|
|
|
|
private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
|
|
new RemoteCallbackList<INetworkManagementEventObserver>();
|
|
|
|
private final NetworkStatsFactory mStatsFactory = new NetworkStatsFactory();
|
|
|
|
private Object mQuotaLock = new Object();
|
|
/** Set of interfaces with active quotas. */
|
|
private HashMap<String, Long> mActiveQuotas = Maps.newHashMap();
|
|
/** Set of interfaces with active alerts. */
|
|
private HashMap<String, Long> mActiveAlerts = Maps.newHashMap();
|
|
/** Set of UIDs with active reject rules. */
|
|
private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
|
|
|
|
private Object mIdleTimerLock = new Object();
|
|
/** Set of interfaces with active idle timers. */
|
|
private static class IdleTimerParams {
|
|
public final int timeout;
|
|
public final String label;
|
|
public int networkCount;
|
|
|
|
IdleTimerParams(int timeout, String label) {
|
|
this.timeout = timeout;
|
|
this.label = label;
|
|
this.networkCount = 1;
|
|
}
|
|
}
|
|
private HashMap<String, IdleTimerParams> mActiveIdleTimers = Maps.newHashMap();
|
|
|
|
private volatile boolean mBandwidthControlEnabled;
|
|
private volatile boolean mFirewallEnabled;
|
|
|
|
/**
|
|
* Constructs a new NetworkManagementService instance
|
|
*
|
|
* @param context Binder context for this service
|
|
*/
|
|
private NetworkManagementService(Context context, String socket) {
|
|
mContext = context;
|
|
|
|
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
|
|
return;
|
|
}
|
|
|
|
mConnector = new NativeDaemonConnector(
|
|
new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160);
|
|
mThread = new Thread(mConnector, NETD_TAG);
|
|
|
|
// Add ourself to the Watchdog monitors.
|
|
Watchdog.getInstance().addMonitor(this);
|
|
}
|
|
|
|
static NetworkManagementService create(Context context,
|
|
String socket) throws InterruptedException {
|
|
final NetworkManagementService service = new NetworkManagementService(context, socket);
|
|
final CountDownLatch connectedSignal = service.mConnectedSignal;
|
|
if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
|
|
service.mThread.start();
|
|
if (DBG) Slog.d(TAG, "Awaiting socket connection");
|
|
connectedSignal.await();
|
|
if (DBG) Slog.d(TAG, "Connected");
|
|
return service;
|
|
}
|
|
|
|
public static NetworkManagementService create(Context context) throws InterruptedException {
|
|
return create(context, NETD_SOCKET_NAME);
|
|
}
|
|
|
|
public void systemReady() {
|
|
prepareNativeDaemon();
|
|
if (DBG) Slog.d(TAG, "Prepared");
|
|
}
|
|
|
|
@Override
|
|
public void registerObserver(INetworkManagementEventObserver observer) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
mObservers.register(observer);
|
|
}
|
|
|
|
@Override
|
|
public void unregisterObserver(INetworkManagementEventObserver observer) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
mObservers.unregister(observer);
|
|
}
|
|
|
|
/**
|
|
* Notify our observers of an interface status change
|
|
*/
|
|
private void notifyInterfaceStatusChanged(String iface, boolean up) {
|
|
final int length = mObservers.beginBroadcast();
|
|
for (int i = 0; i < length; i++) {
|
|
try {
|
|
mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
|
|
} catch (RemoteException e) {
|
|
} catch (RuntimeException e) {
|
|
}
|
|
}
|
|
mObservers.finishBroadcast();
|
|
}
|
|
|
|
/**
|
|
* Notify our observers of an interface link state change
|
|
* (typically, an Ethernet cable has been plugged-in or unplugged).
|
|
*/
|
|
private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
|
|
final int length = mObservers.beginBroadcast();
|
|
for (int i = 0; i < length; i++) {
|
|
try {
|
|
mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
|
|
} catch (RemoteException e) {
|
|
} catch (RuntimeException e) {
|
|
}
|
|
}
|
|
mObservers.finishBroadcast();
|
|
}
|
|
|
|
/**
|
|
* Notify our observers of an interface addition.
|
|
*/
|
|
private void notifyInterfaceAdded(String iface) {
|
|
final int length = mObservers.beginBroadcast();
|
|
for (int i = 0; i < length; i++) {
|
|
try {
|
|
mObservers.getBroadcastItem(i).interfaceAdded(iface);
|
|
} catch (RemoteException e) {
|
|
} catch (RuntimeException e) {
|
|
}
|
|
}
|
|
mObservers.finishBroadcast();
|
|
}
|
|
|
|
/**
|
|
* Notify our observers of an interface removal.
|
|
*/
|
|
private void notifyInterfaceRemoved(String iface) {
|
|
// netd already clears out quota and alerts for removed ifaces; update
|
|
// our sanity-checking state.
|
|
mActiveAlerts.remove(iface);
|
|
mActiveQuotas.remove(iface);
|
|
|
|
final int length = mObservers.beginBroadcast();
|
|
for (int i = 0; i < length; i++) {
|
|
try {
|
|
mObservers.getBroadcastItem(i).interfaceRemoved(iface);
|
|
} catch (RemoteException e) {
|
|
} catch (RuntimeException e) {
|
|
}
|
|
}
|
|
mObservers.finishBroadcast();
|
|
}
|
|
|
|
/**
|
|
* Notify our observers of a limit reached.
|
|
*/
|
|
private void notifyLimitReached(String limitName, String iface) {
|
|
final int length = mObservers.beginBroadcast();
|
|
for (int i = 0; i < length; i++) {
|
|
try {
|
|
mObservers.getBroadcastItem(i).limitReached(limitName, iface);
|
|
} catch (RemoteException e) {
|
|
} catch (RuntimeException e) {
|
|
}
|
|
}
|
|
mObservers.finishBroadcast();
|
|
}
|
|
|
|
/**
|
|
* Notify our observers of a change in the data activity state of the interface
|
|
*/
|
|
private void notifyInterfaceClassActivity(String label, boolean active) {
|
|
final int length = mObservers.beginBroadcast();
|
|
for (int i = 0; i < length; i++) {
|
|
try {
|
|
mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(label, active);
|
|
} catch (RemoteException e) {
|
|
} catch (RuntimeException e) {
|
|
}
|
|
}
|
|
mObservers.finishBroadcast();
|
|
}
|
|
|
|
/**
|
|
* Prepare native daemon once connected, enabling modules and pushing any
|
|
* existing in-memory rules.
|
|
*/
|
|
private void prepareNativeDaemon() {
|
|
mBandwidthControlEnabled = false;
|
|
|
|
// only enable bandwidth control when support exists
|
|
final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
|
|
if (hasKernelSupport) {
|
|
Slog.d(TAG, "enabling bandwidth control");
|
|
try {
|
|
mConnector.execute("bandwidth", "enable");
|
|
mBandwidthControlEnabled = true;
|
|
} catch (NativeDaemonConnectorException e) {
|
|
Log.wtf(TAG, "problem enabling bandwidth controls", e);
|
|
}
|
|
} else {
|
|
Slog.d(TAG, "not enabling bandwidth control");
|
|
}
|
|
|
|
SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
|
|
|
|
if (mBandwidthControlEnabled) {
|
|
try {
|
|
IBatteryStats.Stub.asInterface(ServiceManager.getService(BatteryStats.SERVICE_NAME))
|
|
.noteNetworkStatsEnabled();
|
|
} catch (RemoteException e) {
|
|
}
|
|
}
|
|
|
|
// push any existing quota or UID rules
|
|
synchronized (mQuotaLock) {
|
|
int size = mActiveQuotas.size();
|
|
if (size > 0) {
|
|
Slog.d(TAG, "pushing " + size + " active quota rules");
|
|
final HashMap<String, Long> activeQuotas = mActiveQuotas;
|
|
mActiveQuotas = Maps.newHashMap();
|
|
for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
|
|
setInterfaceQuota(entry.getKey(), entry.getValue());
|
|
}
|
|
}
|
|
|
|
size = mActiveAlerts.size();
|
|
if (size > 0) {
|
|
Slog.d(TAG, "pushing " + size + " active alert rules");
|
|
final HashMap<String, Long> activeAlerts = mActiveAlerts;
|
|
mActiveAlerts = Maps.newHashMap();
|
|
for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
|
|
setInterfaceAlert(entry.getKey(), entry.getValue());
|
|
}
|
|
}
|
|
|
|
size = mUidRejectOnQuota.size();
|
|
if (size > 0) {
|
|
Slog.d(TAG, "pushing " + size + " active uid rules");
|
|
final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota;
|
|
mUidRejectOnQuota = new SparseBooleanArray();
|
|
for (int i = 0; i < uidRejectOnQuota.size(); i++) {
|
|
setUidNetworkRules(uidRejectOnQuota.keyAt(i), uidRejectOnQuota.valueAt(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Push any existing firewall state
|
|
setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
|
|
}
|
|
|
|
/**
|
|
* Notify our observers of a new or updated interface address.
|
|
*/
|
|
private void notifyAddressUpdated(String iface, LinkAddress address) {
|
|
final int length = mObservers.beginBroadcast();
|
|
for (int i = 0; i < length; i++) {
|
|
try {
|
|
mObservers.getBroadcastItem(i).addressUpdated(iface, address);
|
|
} catch (RemoteException e) {
|
|
} catch (RuntimeException e) {
|
|
}
|
|
}
|
|
mObservers.finishBroadcast();
|
|
}
|
|
|
|
/**
|
|
* Notify our observers of a deleted interface address.
|
|
*/
|
|
private void notifyAddressRemoved(String iface, LinkAddress address) {
|
|
final int length = mObservers.beginBroadcast();
|
|
for (int i = 0; i < length; i++) {
|
|
try {
|
|
mObservers.getBroadcastItem(i).addressRemoved(iface, address);
|
|
} catch (RemoteException e) {
|
|
} catch (RuntimeException e) {
|
|
}
|
|
}
|
|
mObservers.finishBroadcast();
|
|
}
|
|
|
|
/**
|
|
* Notify our observers of DNS server information received.
|
|
*/
|
|
private void notifyInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
|
|
final int length = mObservers.beginBroadcast();
|
|
for (int i = 0; i < length; i++) {
|
|
try {
|
|
mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime, addresses);
|
|
} catch (RemoteException e) {
|
|
} catch (RuntimeException e) {
|
|
}
|
|
}
|
|
mObservers.finishBroadcast();
|
|
}
|
|
|
|
//
|
|
// Netd Callback handling
|
|
//
|
|
|
|
private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
|
|
@Override
|
|
public void onDaemonConnected() {
|
|
// event is dispatched from internal NDC thread, so we prepare the
|
|
// daemon back on main thread.
|
|
if (mConnectedSignal != null) {
|
|
mConnectedSignal.countDown();
|
|
mConnectedSignal = null;
|
|
} else {
|
|
mMainHandler.post(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
prepareNativeDaemon();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onEvent(int code, String raw, String[] cooked) {
|
|
String errorMessage = String.format("Invalid event from daemon (%s)", raw);
|
|
switch (code) {
|
|
case NetdResponseCode.InterfaceChange:
|
|
/*
|
|
* a network interface change occured
|
|
* Format: "NNN Iface added <name>"
|
|
* "NNN Iface removed <name>"
|
|
* "NNN Iface changed <name> <up/down>"
|
|
* "NNN Iface linkstatus <name> <up/down>"
|
|
*/
|
|
if (cooked.length < 4 || !cooked[1].equals("Iface")) {
|
|
throw new IllegalStateException(errorMessage);
|
|
}
|
|
if (cooked[2].equals("added")) {
|
|
notifyInterfaceAdded(cooked[3]);
|
|
return true;
|
|
} else if (cooked[2].equals("removed")) {
|
|
notifyInterfaceRemoved(cooked[3]);
|
|
return true;
|
|
} else if (cooked[2].equals("changed") && cooked.length == 5) {
|
|
notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
|
|
return true;
|
|
} else if (cooked[2].equals("linkstate") && cooked.length == 5) {
|
|
notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
|
|
return true;
|
|
}
|
|
throw new IllegalStateException(errorMessage);
|
|
// break;
|
|
case NetdResponseCode.BandwidthControl:
|
|
/*
|
|
* Bandwidth control needs some attention
|
|
* Format: "NNN limit alert <alertName> <ifaceName>"
|
|
*/
|
|
if (cooked.length < 5 || !cooked[1].equals("limit")) {
|
|
throw new IllegalStateException(errorMessage);
|
|
}
|
|
if (cooked[2].equals("alert")) {
|
|
notifyLimitReached(cooked[3], cooked[4]);
|
|
return true;
|
|
}
|
|
throw new IllegalStateException(errorMessage);
|
|
// break;
|
|
case NetdResponseCode.InterfaceClassActivity:
|
|
/*
|
|
* An network interface class state changed (active/idle)
|
|
* Format: "NNN IfaceClass <active/idle> <label>"
|
|
*/
|
|
if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {
|
|
throw new IllegalStateException(errorMessage);
|
|
}
|
|
boolean isActive = cooked[2].equals("active");
|
|
notifyInterfaceClassActivity(cooked[3], isActive);
|
|
return true;
|
|
// break;
|
|
case NetdResponseCode.InterfaceAddressChange:
|
|
/*
|
|
* A network address change occurred
|
|
* Format: "NNN Address updated <addr> <iface> <flags> <scope>"
|
|
* "NNN Address removed <addr> <iface> <flags> <scope>"
|
|
*/
|
|
if (cooked.length < 7 || !cooked[1].equals("Address")) {
|
|
throw new IllegalStateException(errorMessage);
|
|
}
|
|
|
|
String iface = cooked[4];
|
|
LinkAddress address;
|
|
try {
|
|
int flags = Integer.parseInt(cooked[5]);
|
|
int scope = Integer.parseInt(cooked[6]);
|
|
address = new LinkAddress(cooked[3], flags, scope);
|
|
} catch(NumberFormatException e) { // Non-numeric lifetime or scope.
|
|
throw new IllegalStateException(errorMessage, e);
|
|
} catch(IllegalArgumentException e) { // Malformed/invalid IP address.
|
|
throw new IllegalStateException(errorMessage, e);
|
|
}
|
|
|
|
if (cooked[2].equals("updated")) {
|
|
notifyAddressUpdated(iface, address);
|
|
} else {
|
|
notifyAddressRemoved(iface, address);
|
|
}
|
|
return true;
|
|
// break;
|
|
case NetdResponseCode.InterfaceDnsServerInfo:
|
|
/*
|
|
* Information about available DNS servers has been received.
|
|
* Format: "NNN DnsInfo servers <interface> <lifetime> <servers>"
|
|
*/
|
|
long lifetime; // Actually a 32-bit unsigned integer.
|
|
|
|
if (cooked.length == 6 &&
|
|
cooked[1].equals("DnsInfo") &&
|
|
cooked[2].equals("servers")) {
|
|
try {
|
|
lifetime = Long.parseLong(cooked[4]);
|
|
} catch (NumberFormatException e) {
|
|
throw new IllegalStateException(errorMessage);
|
|
}
|
|
String[] servers = cooked[5].split(",");
|
|
notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers);
|
|
}
|
|
return true;
|
|
// break;
|
|
default: break;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// INetworkManagementService members
|
|
//
|
|
|
|
@Override
|
|
public String[] listInterfaces() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
return NativeDaemonEvent.filterMessageList(
|
|
mConnector.executeForList("interface", "list"), InterfaceListResult);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public InterfaceConfiguration getInterfaceConfig(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
final NativeDaemonEvent event;
|
|
try {
|
|
event = mConnector.execute("interface", "getcfg", iface);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
|
|
event.checkCode(InterfaceGetCfgResult);
|
|
|
|
// Rsp: 213 xx:xx:xx:xx:xx:xx yyy.yyy.yyy.yyy zzz flag1 flag2 flag3
|
|
final StringTokenizer st = new StringTokenizer(event.getMessage());
|
|
|
|
InterfaceConfiguration cfg;
|
|
try {
|
|
cfg = new InterfaceConfiguration();
|
|
cfg.setHardwareAddress(st.nextToken(" "));
|
|
InetAddress addr = null;
|
|
int prefixLength = 0;
|
|
try {
|
|
addr = NetworkUtils.numericToInetAddress(st.nextToken());
|
|
} catch (IllegalArgumentException iae) {
|
|
Slog.e(TAG, "Failed to parse ipaddr", iae);
|
|
}
|
|
|
|
try {
|
|
prefixLength = Integer.parseInt(st.nextToken());
|
|
} catch (NumberFormatException nfe) {
|
|
Slog.e(TAG, "Failed to parse prefixLength", nfe);
|
|
}
|
|
|
|
cfg.setLinkAddress(new LinkAddress(addr, prefixLength));
|
|
while (st.hasMoreTokens()) {
|
|
cfg.setFlag(st.nextToken());
|
|
}
|
|
} catch (NoSuchElementException nsee) {
|
|
throw new IllegalStateException("Invalid response from daemon: " + event);
|
|
}
|
|
return cfg;
|
|
}
|
|
|
|
@Override
|
|
public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
LinkAddress linkAddr = cfg.getLinkAddress();
|
|
if (linkAddr == null || linkAddr.getAddress() == null) {
|
|
throw new IllegalStateException("Null LinkAddress given");
|
|
}
|
|
|
|
final Command cmd = new Command("interface", "setcfg", iface,
|
|
linkAddr.getAddress().getHostAddress(),
|
|
linkAddr.getNetworkPrefixLength());
|
|
for (String flag : cfg.getFlags()) {
|
|
cmd.appendArg(flag);
|
|
}
|
|
|
|
try {
|
|
mConnector.execute(cmd);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setInterfaceDown(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
|
|
ifcg.setInterfaceDown();
|
|
setInterfaceConfig(iface, ifcg);
|
|
}
|
|
|
|
@Override
|
|
public void setInterfaceUp(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
|
|
ifcg.setInterfaceUp();
|
|
setInterfaceConfig(iface, ifcg);
|
|
}
|
|
|
|
@Override
|
|
public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute(
|
|
"interface", "ipv6privacyextensions", iface, enable ? "enable" : "disable");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
/* TODO: This is right now a IPv4 only function. Works for wifi which loses its
|
|
IPv6 addresses on interface down, but we need to do full clean up here */
|
|
@Override
|
|
public void clearInterfaceAddresses(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("interface", "clearaddrs", iface);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void enableIpv6(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("interface", "ipv6", iface, "enable");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void disableIpv6(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("interface", "ipv6", iface, "disable");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void addRoute(String interfaceName, RouteInfo route) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
modifyRoute(interfaceName, ADD, route, DEFAULT);
|
|
}
|
|
|
|
@Override
|
|
public void removeRoute(String interfaceName, RouteInfo route) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
modifyRoute(interfaceName, REMOVE, route, DEFAULT);
|
|
}
|
|
|
|
@Override
|
|
public void addSecondaryRoute(String interfaceName, RouteInfo route) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
modifyRoute(interfaceName, ADD, route, SECONDARY);
|
|
}
|
|
|
|
@Override
|
|
public void removeSecondaryRoute(String interfaceName, RouteInfo route) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
modifyRoute(interfaceName, REMOVE, route, SECONDARY);
|
|
}
|
|
|
|
private void modifyRoute(String interfaceName, String action, RouteInfo route, String type) {
|
|
final Command cmd = new Command("interface", "route", action, interfaceName, type);
|
|
|
|
// create triplet: dest-ip-addr prefixlength gateway-ip-addr
|
|
final LinkAddress la = route.getDestination();
|
|
cmd.appendArg(la.getAddress().getHostAddress());
|
|
cmd.appendArg(la.getNetworkPrefixLength());
|
|
|
|
if (route.getGateway() == null) {
|
|
if (la.getAddress() instanceof Inet4Address) {
|
|
cmd.appendArg("0.0.0.0");
|
|
} else {
|
|
cmd.appendArg("::0");
|
|
}
|
|
} else {
|
|
cmd.appendArg(route.getGateway().getHostAddress());
|
|
}
|
|
|
|
try {
|
|
mConnector.execute(cmd);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
private ArrayList<String> readRouteList(String filename) {
|
|
FileInputStream fstream = null;
|
|
ArrayList<String> list = new ArrayList<String>();
|
|
|
|
try {
|
|
fstream = new FileInputStream(filename);
|
|
DataInputStream in = new DataInputStream(fstream);
|
|
BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
|
String s;
|
|
|
|
// throw away the title line
|
|
|
|
while (((s = br.readLine()) != null) && (s.length() != 0)) {
|
|
list.add(s);
|
|
}
|
|
} catch (IOException ex) {
|
|
// return current list, possibly empty
|
|
} finally {
|
|
if (fstream != null) {
|
|
try {
|
|
fstream.close();
|
|
} catch (IOException ex) {}
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
@Override
|
|
public RouteInfo[] getRoutes(String interfaceName) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
|
|
|
|
// v4 routes listed as:
|
|
// iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
|
|
for (String s : readRouteList("/proc/net/route")) {
|
|
String[] fields = s.split("\t");
|
|
|
|
if (fields.length > 7) {
|
|
String iface = fields[0];
|
|
|
|
if (interfaceName.equals(iface)) {
|
|
String dest = fields[1];
|
|
String gate = fields[2];
|
|
String flags = fields[3]; // future use?
|
|
String mask = fields[7];
|
|
try {
|
|
// address stored as a hex string, ex: 0014A8C0
|
|
InetAddress destAddr =
|
|
NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
|
|
int prefixLength =
|
|
NetworkUtils.netmaskIntToPrefixLength(
|
|
(int)Long.parseLong(mask, 16));
|
|
LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
|
|
|
|
// address stored as a hex string, ex 0014A8C0
|
|
InetAddress gatewayAddr =
|
|
NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
|
|
|
|
RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
|
|
routes.add(route);
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Error parsing route " + s + " : " + e);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// v6 routes listed as:
|
|
// dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
|
|
for (String s : readRouteList("/proc/net/ipv6_route")) {
|
|
String[]fields = s.split("\\s+");
|
|
if (fields.length > 9) {
|
|
String iface = fields[9].trim();
|
|
if (interfaceName.equals(iface)) {
|
|
String dest = fields[0];
|
|
String prefix = fields[1];
|
|
String gate = fields[4];
|
|
|
|
try {
|
|
// prefix length stored as a hex string, ex 40
|
|
int prefixLength = Integer.parseInt(prefix, 16);
|
|
|
|
// address stored as a 32 char hex string
|
|
// ex fe800000000000000000000000000000
|
|
InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
|
|
LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
|
|
|
|
InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
|
|
|
|
RouteInfo route = new RouteInfo(linkAddress, gateAddr);
|
|
routes.add(route);
|
|
} catch (Exception e) {
|
|
Log.e(TAG, "Error parsing route " + s + " : " + e);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return routes.toArray(new RouteInfo[routes.size()]);
|
|
}
|
|
|
|
@Override
|
|
public void setMtu(String iface, int mtu) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
final NativeDaemonEvent event;
|
|
try {
|
|
event = mConnector.execute("interface", "setmtu", iface, mtu);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void shutdown() {
|
|
// TODO: remove from aidl if nobody calls externally
|
|
mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
|
|
|
|
Slog.d(TAG, "Shutting down");
|
|
}
|
|
|
|
@Override
|
|
public boolean getIpForwardingEnabled() throws IllegalStateException{
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
final NativeDaemonEvent event;
|
|
try {
|
|
event = mConnector.execute("ipfwd", "status");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
|
|
// 211 Forwarding enabled
|
|
event.checkCode(IpFwdStatusResult);
|
|
return event.getMessage().endsWith("enabled");
|
|
}
|
|
|
|
@Override
|
|
public void setIpForwardingEnabled(boolean enable) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("ipfwd", enable ? "enable" : "disable");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void startTethering(String[] dhcpRange) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
// cmd is "tether start first_start first_stop second_start second_stop ..."
|
|
// an odd number of addrs will fail
|
|
|
|
final Command cmd = new Command("tether", "start");
|
|
for (String d : dhcpRange) {
|
|
cmd.appendArg(d);
|
|
}
|
|
|
|
try {
|
|
mConnector.execute(cmd);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void stopTethering() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("tether", "stop");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isTetheringStarted() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
final NativeDaemonEvent event;
|
|
try {
|
|
event = mConnector.execute("tether", "status");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
|
|
// 210 Tethering services started
|
|
event.checkCode(TetherStatusResult);
|
|
return event.getMessage().endsWith("started");
|
|
}
|
|
|
|
@Override
|
|
public void tetherInterface(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("tether", "interface", "add", iface);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void untetherInterface(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("tether", "interface", "remove", iface);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String[] listTetheredInterfaces() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
return NativeDaemonEvent.filterMessageList(
|
|
mConnector.executeForList("tether", "interface", "list"),
|
|
TetherInterfaceListResult);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setDnsForwarders(String[] dns) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
final Command cmd = new Command("tether", "dns", "set");
|
|
for (String s : dns) {
|
|
cmd.appendArg(NetworkUtils.numericToInetAddress(s).getHostAddress());
|
|
}
|
|
|
|
try {
|
|
mConnector.execute(cmd);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String[] getDnsForwarders() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
return NativeDaemonEvent.filterMessageList(
|
|
mConnector.executeForList("tether", "dns", "list"), TetherDnsFwdTgtListResult);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
|
|
ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size());
|
|
for (InterfaceAddress ia : addresses) {
|
|
if (!ia.getAddress().isLinkLocalAddress())
|
|
filtered.add(ia);
|
|
}
|
|
return filtered;
|
|
}
|
|
|
|
private void modifyNat(String action, String internalInterface, String externalInterface)
|
|
throws SocketException {
|
|
final Command cmd = new Command("nat", action, internalInterface, externalInterface);
|
|
|
|
final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
|
|
internalInterface);
|
|
if (internalNetworkInterface == null) {
|
|
cmd.appendArg("0");
|
|
} else {
|
|
// Don't touch link-local routes, as link-local addresses aren't routable,
|
|
// kernel creates link-local routes on all interfaces automatically
|
|
List<InterfaceAddress> interfaceAddresses = excludeLinkLocal(
|
|
internalNetworkInterface.getInterfaceAddresses());
|
|
cmd.appendArg(interfaceAddresses.size());
|
|
for (InterfaceAddress ia : interfaceAddresses) {
|
|
InetAddress addr = NetworkUtils.getNetworkPart(
|
|
ia.getAddress(), ia.getNetworkPrefixLength());
|
|
cmd.appendArg(addr.getHostAddress() + "/" + ia.getNetworkPrefixLength());
|
|
}
|
|
}
|
|
|
|
try {
|
|
mConnector.execute(cmd);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void enableNat(String internalInterface, String externalInterface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
modifyNat("enable", internalInterface, externalInterface);
|
|
} catch (SocketException e) {
|
|
throw new IllegalStateException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void disableNat(String internalInterface, String externalInterface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
modifyNat("disable", internalInterface, externalInterface);
|
|
} catch (SocketException e) {
|
|
throw new IllegalStateException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String[] listTtys() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
return NativeDaemonEvent.filterMessageList(
|
|
mConnector.executeForList("list_ttys"), TtyListResult);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void attachPppd(
|
|
String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("pppd", "attach", tty,
|
|
NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
|
|
NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
|
|
NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
|
|
NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void detachPppd(String tty) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("pppd", "detach", tty);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void startAccessPoint(
|
|
WifiConfiguration wifiConfig, String wlanIface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
wifiFirmwareReload(wlanIface, "AP");
|
|
if (wifiConfig == null) {
|
|
mConnector.execute("softap", "set", wlanIface);
|
|
} else {
|
|
mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
|
|
"broadcast", "6", getSecurityType(wifiConfig),
|
|
new SensitiveArg(wifiConfig.preSharedKey));
|
|
}
|
|
mConnector.execute("softap", "startap");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
private static String getSecurityType(WifiConfiguration wifiConfig) {
|
|
switch (wifiConfig.getAuthType()) {
|
|
case KeyMgmt.WPA_PSK:
|
|
return "wpa-psk";
|
|
case KeyMgmt.WPA2_PSK:
|
|
return "wpa2-psk";
|
|
default:
|
|
return "open";
|
|
}
|
|
}
|
|
|
|
/* @param mode can be "AP", "STA" or "P2P" */
|
|
@Override
|
|
public void wifiFirmwareReload(String wlanIface, String mode) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("softap", "fwreload", wlanIface, mode);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void stopAccessPoint(String wlanIface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("softap", "stopap");
|
|
wifiFirmwareReload(wlanIface, "STA");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
if (wifiConfig == null) {
|
|
mConnector.execute("softap", "set", wlanIface);
|
|
} else {
|
|
mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
|
|
"broadcast", "6", getSecurityType(wifiConfig),
|
|
new SensitiveArg(wifiConfig.preSharedKey));
|
|
}
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void addIdleTimer(String iface, int timeout, String label) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
if (DBG) Slog.d(TAG, "Adding idletimer");
|
|
|
|
synchronized (mIdleTimerLock) {
|
|
IdleTimerParams params = mActiveIdleTimers.get(iface);
|
|
if (params != null) {
|
|
// the interface already has idletimer, update network count
|
|
params.networkCount++;
|
|
return;
|
|
}
|
|
|
|
try {
|
|
mConnector.execute("idletimer", "add", iface, Integer.toString(timeout), label);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, label));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void removeIdleTimer(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
if (DBG) Slog.d(TAG, "Removing idletimer");
|
|
|
|
synchronized (mIdleTimerLock) {
|
|
IdleTimerParams params = mActiveIdleTimers.get(iface);
|
|
if (params == null || --(params.networkCount) > 0) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
mConnector.execute("idletimer", "remove", iface,
|
|
Integer.toString(params.timeout), params.label);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
mActiveIdleTimers.remove(iface);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public NetworkStats getNetworkStatsSummaryDev() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
return mStatsFactory.readNetworkStatsSummaryDev();
|
|
} catch (IOException e) {
|
|
throw new IllegalStateException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public NetworkStats getNetworkStatsSummaryXt() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
return mStatsFactory.readNetworkStatsSummaryXt();
|
|
} catch (IOException e) {
|
|
throw new IllegalStateException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public NetworkStats getNetworkStatsDetail() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
return mStatsFactory.readNetworkStatsDetail(UID_ALL);
|
|
} catch (IOException e) {
|
|
throw new IllegalStateException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setInterfaceQuota(String iface, long quotaBytes) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
// silently discard when control disabled
|
|
// TODO: eventually migrate to be always enabled
|
|
if (!mBandwidthControlEnabled) return;
|
|
|
|
synchronized (mQuotaLock) {
|
|
if (mActiveQuotas.containsKey(iface)) {
|
|
throw new IllegalStateException("iface " + iface + " already has quota");
|
|
}
|
|
|
|
try {
|
|
// TODO: support quota shared across interfaces
|
|
mConnector.execute("bandwidth", "setiquota", iface, quotaBytes);
|
|
mActiveQuotas.put(iface, quotaBytes);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void removeInterfaceQuota(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
// silently discard when control disabled
|
|
// TODO: eventually migrate to be always enabled
|
|
if (!mBandwidthControlEnabled) return;
|
|
|
|
synchronized (mQuotaLock) {
|
|
if (!mActiveQuotas.containsKey(iface)) {
|
|
// TODO: eventually consider throwing
|
|
return;
|
|
}
|
|
|
|
mActiveQuotas.remove(iface);
|
|
mActiveAlerts.remove(iface);
|
|
|
|
try {
|
|
// TODO: support quota shared across interfaces
|
|
mConnector.execute("bandwidth", "removeiquota", iface);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setInterfaceAlert(String iface, long alertBytes) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
// silently discard when control disabled
|
|
// TODO: eventually migrate to be always enabled
|
|
if (!mBandwidthControlEnabled) return;
|
|
|
|
// quick sanity check
|
|
if (!mActiveQuotas.containsKey(iface)) {
|
|
throw new IllegalStateException("setting alert requires existing quota on iface");
|
|
}
|
|
|
|
synchronized (mQuotaLock) {
|
|
if (mActiveAlerts.containsKey(iface)) {
|
|
throw new IllegalStateException("iface " + iface + " already has alert");
|
|
}
|
|
|
|
try {
|
|
// TODO: support alert shared across interfaces
|
|
mConnector.execute("bandwidth", "setinterfacealert", iface, alertBytes);
|
|
mActiveAlerts.put(iface, alertBytes);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void removeInterfaceAlert(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
// silently discard when control disabled
|
|
// TODO: eventually migrate to be always enabled
|
|
if (!mBandwidthControlEnabled) return;
|
|
|
|
synchronized (mQuotaLock) {
|
|
if (!mActiveAlerts.containsKey(iface)) {
|
|
// TODO: eventually consider throwing
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// TODO: support alert shared across interfaces
|
|
mConnector.execute("bandwidth", "removeinterfacealert", iface);
|
|
mActiveAlerts.remove(iface);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setGlobalAlert(long alertBytes) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
// silently discard when control disabled
|
|
// TODO: eventually migrate to be always enabled
|
|
if (!mBandwidthControlEnabled) return;
|
|
|
|
try {
|
|
mConnector.execute("bandwidth", "setglobalalert", alertBytes);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
// silently discard when control disabled
|
|
// TODO: eventually migrate to be always enabled
|
|
if (!mBandwidthControlEnabled) return;
|
|
|
|
synchronized (mQuotaLock) {
|
|
final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
|
|
if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
|
|
// TODO: eventually consider throwing
|
|
return;
|
|
}
|
|
|
|
try {
|
|
mConnector.execute("bandwidth",
|
|
rejectOnQuotaInterfaces ? "addnaughtyapps" : "removenaughtyapps", uid);
|
|
if (rejectOnQuotaInterfaces) {
|
|
mUidRejectOnQuota.put(uid, true);
|
|
} else {
|
|
mUidRejectOnQuota.delete(uid);
|
|
}
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isBandwidthControlEnabled() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
return mBandwidthControlEnabled;
|
|
}
|
|
|
|
@Override
|
|
public NetworkStats getNetworkStatsUidDetail(int uid) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
return mStatsFactory.readNetworkStatsDetail(uid);
|
|
} catch (IOException e) {
|
|
throw new IllegalStateException(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public NetworkStats getNetworkStatsTethering() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
|
|
try {
|
|
final NativeDaemonEvent[] events = mConnector.executeForList(
|
|
"bandwidth", "gettetherstats");
|
|
for (NativeDaemonEvent event : events) {
|
|
if (event.getCode() != TetheringStatsListResult) continue;
|
|
|
|
// 114 ifaceIn ifaceOut rx_bytes rx_packets tx_bytes tx_packets
|
|
final StringTokenizer tok = new StringTokenizer(event.getMessage());
|
|
try {
|
|
final String ifaceIn = tok.nextToken();
|
|
final String ifaceOut = tok.nextToken();
|
|
|
|
final NetworkStats.Entry entry = new NetworkStats.Entry();
|
|
entry.iface = ifaceOut;
|
|
entry.uid = UID_TETHERING;
|
|
entry.set = SET_DEFAULT;
|
|
entry.tag = TAG_NONE;
|
|
entry.rxBytes = Long.parseLong(tok.nextToken());
|
|
entry.rxPackets = Long.parseLong(tok.nextToken());
|
|
entry.txBytes = Long.parseLong(tok.nextToken());
|
|
entry.txPackets = Long.parseLong(tok.nextToken());
|
|
stats.combineValues(entry);
|
|
} catch (NoSuchElementException e) {
|
|
throw new IllegalStateException("problem parsing tethering stats: " + event);
|
|
} catch (NumberFormatException e) {
|
|
throw new IllegalStateException("problem parsing tethering stats: " + event);
|
|
}
|
|
}
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
return stats;
|
|
}
|
|
|
|
@Override
|
|
public void setDefaultInterfaceForDns(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("resolver", "setdefaultif", iface);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setDnsServersForInterface(String iface, String[] servers, String domains) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
final Command cmd = new Command("resolver", "setifdns", iface,
|
|
(domains == null ? "" : domains));
|
|
|
|
for (String s : servers) {
|
|
InetAddress a = NetworkUtils.numericToInetAddress(s);
|
|
if (a.isAnyLocalAddress() == false) {
|
|
cmd.appendArg(a.getHostAddress());
|
|
}
|
|
}
|
|
|
|
try {
|
|
mConnector.execute(cmd);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setUidRangeRoute(String iface, int uid_start, int uid_end) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("interface", "fwmark",
|
|
"uid", "add", iface, uid_start, uid_end);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearUidRangeRoute(String iface, int uid_start, int uid_end) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("interface", "fwmark",
|
|
"uid", "remove", iface, uid_start, uid_end);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setMarkedForwarding(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("interface", "fwmark", "rule", "add", iface);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearMarkedForwarding(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("interface", "fwmark", "rule", "remove", iface);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getMarkForUid(int uid) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
final NativeDaemonEvent event;
|
|
try {
|
|
event = mConnector.execute("interface", "fwmark", "get", "mark", uid);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
event.checkCode(GetMarkResult);
|
|
return Integer.parseInt(event.getMessage());
|
|
}
|
|
|
|
@Override
|
|
public int getMarkForProtect() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
final NativeDaemonEvent event;
|
|
try {
|
|
event = mConnector.execute("interface", "fwmark", "get", "protect");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
event.checkCode(GetMarkResult);
|
|
return Integer.parseInt(event.getMessage());
|
|
}
|
|
|
|
@Override
|
|
public void setMarkedForwardingRoute(String iface, RouteInfo route) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
LinkAddress dest = route.getDestination();
|
|
mConnector.execute("interface", "fwmark", "route", "add", iface,
|
|
dest.getAddress().getHostAddress(), dest.getNetworkPrefixLength());
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearMarkedForwardingRoute(String iface, RouteInfo route) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
LinkAddress dest = route.getDestination();
|
|
mConnector.execute("interface", "fwmark", "route", "remove", iface,
|
|
dest.getAddress().getHostAddress(), dest.getNetworkPrefixLength());
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setHostExemption(LinkAddress host) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("interface", "fwmark", "exempt", "add", host);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearHostExemption(LinkAddress host) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("interface", "fwmark", "exempt", "remove", host);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("resolver", "setifaceforuidrange", iface, uid_start, uid_end);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearDnsInterfaceForUidRange(int uid_start, int uid_end) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("resolver", "clearifaceforuidrange", uid_start, uid_end);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearDnsInterfaceMaps() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("resolver", "clearifacemapping");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
public void flushDefaultDnsCache() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("resolver", "flushdefaultif");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void flushInterfaceDnsCache(String iface) {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("resolver", "flushif", iface);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setFirewallEnabled(boolean enabled) {
|
|
enforceSystemUid();
|
|
try {
|
|
mConnector.execute("firewall", enabled ? "enable" : "disable");
|
|
mFirewallEnabled = enabled;
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isFirewallEnabled() {
|
|
enforceSystemUid();
|
|
return mFirewallEnabled;
|
|
}
|
|
|
|
@Override
|
|
public void setFirewallInterfaceRule(String iface, boolean allow) {
|
|
enforceSystemUid();
|
|
Preconditions.checkState(mFirewallEnabled);
|
|
final String rule = allow ? ALLOW : DENY;
|
|
try {
|
|
mConnector.execute("firewall", "set_interface_rule", iface, rule);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setFirewallEgressSourceRule(String addr, boolean allow) {
|
|
enforceSystemUid();
|
|
Preconditions.checkState(mFirewallEnabled);
|
|
final String rule = allow ? ALLOW : DENY;
|
|
try {
|
|
mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
|
|
enforceSystemUid();
|
|
Preconditions.checkState(mFirewallEnabled);
|
|
final String rule = allow ? ALLOW : DENY;
|
|
try {
|
|
mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setFirewallUidRule(int uid, boolean allow) {
|
|
enforceSystemUid();
|
|
Preconditions.checkState(mFirewallEnabled);
|
|
final String rule = allow ? ALLOW : DENY;
|
|
try {
|
|
mConnector.execute("firewall", "set_uid_rule", uid, rule);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
private static void enforceSystemUid() {
|
|
final int uid = Binder.getCallingUid();
|
|
if (uid != Process.SYSTEM_UID) {
|
|
throw new SecurityException("Only available to AID_SYSTEM");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setDnsInterfaceForPid(String iface, int pid) throws IllegalStateException {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("resolver", "setifaceforpid", iface, pid);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw new IllegalStateException(
|
|
"Error communicating with native deamon to set interface for pid" + iface, e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearDnsInterfaceForPid(int pid) throws IllegalStateException {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
try {
|
|
mConnector.execute("resolver", "clearifaceforpid", pid);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw new IllegalStateException(
|
|
"Error communicating with native deamon to clear interface for pid " + pid, e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void startClatd(String interfaceName) throws IllegalStateException {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
try {
|
|
mConnector.execute("clatd", "start", interfaceName);
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void stopClatd() throws IllegalStateException {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
try {
|
|
mConnector.execute("clatd", "stop");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isClatdStarted() {
|
|
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
|
|
|
|
final NativeDaemonEvent event;
|
|
try {
|
|
event = mConnector.execute("clatd", "status");
|
|
} catch (NativeDaemonConnectorException e) {
|
|
throw e.rethrowAsParcelableException();
|
|
}
|
|
|
|
event.checkCode(ClatdStatusResult);
|
|
return event.getMessage().endsWith("started");
|
|
}
|
|
|
|
/** {@inheritDoc} */
|
|
@Override
|
|
public void monitor() {
|
|
if (mConnector != null) {
|
|
mConnector.monitor();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
|
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
|
|
|
|
pw.println("NetworkManagementService NativeDaemonConnector Log:");
|
|
mConnector.dump(fd, pw, args);
|
|
pw.println();
|
|
|
|
pw.print("Bandwidth control enabled: "); pw.println(mBandwidthControlEnabled);
|
|
|
|
synchronized (mQuotaLock) {
|
|
pw.print("Active quota ifaces: "); pw.println(mActiveQuotas.toString());
|
|
pw.print("Active alert ifaces: "); pw.println(mActiveAlerts.toString());
|
|
}
|
|
|
|
synchronized (mUidRejectOnQuota) {
|
|
pw.print("UID reject on quota ifaces: [");
|
|
final int size = mUidRejectOnQuota.size();
|
|
for (int i = 0; i < size; i++) {
|
|
pw.print(mUidRejectOnQuota.keyAt(i));
|
|
if (i < size - 1) pw.print(",");
|
|
}
|
|
pw.println("]");
|
|
}
|
|
|
|
pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
|
|
}
|
|
}
|