Merge changes Ie66ba631,Ic42c09a3
* changes: Implement TestNetworkService Add shell TestNetworkManager and Service
This commit is contained in:
74
core/java/android/net/TestNetworkInterface.java
Normal file
74
core/java/android/net/TestNetworkInterface.java
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.net;
|
||||||
|
|
||||||
|
import android.annotation.TestApi;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to return the interface name and fd of the test interface
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@TestApi
|
||||||
|
public final class TestNetworkInterface implements Parcelable {
|
||||||
|
private static final String TAG = "TestNetworkInterface";
|
||||||
|
|
||||||
|
private final ParcelFileDescriptor mFileDescriptor;
|
||||||
|
private final String mInterfaceName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return (mFileDescriptor != null) ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
|
out.writeParcelable(mFileDescriptor, PARCELABLE_WRITE_RETURN_VALUE);
|
||||||
|
out.writeString(mInterfaceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestNetworkInterface(ParcelFileDescriptor pfd, String intf) {
|
||||||
|
mFileDescriptor = pfd;
|
||||||
|
mInterfaceName = intf;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestNetworkInterface(Parcel in) {
|
||||||
|
mFileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
|
||||||
|
mInterfaceName = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParcelFileDescriptor getFileDescriptor() {
|
||||||
|
return mFileDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInterfaceName() {
|
||||||
|
return mInterfaceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<TestNetworkInterface> CREATOR =
|
||||||
|
new Parcelable.Creator<TestNetworkInterface>() {
|
||||||
|
public TestNetworkInterface createFromParcel(Parcel in) {
|
||||||
|
return new TestNetworkInterface(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestNetworkInterface[] newArray(int size) {
|
||||||
|
return new TestNetworkInterface[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
91
core/java/android/net/TestNetworkManager.java
Normal file
91
core/java/android/net/TestNetworkManager.java
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 android.net;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.TestApi;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
import com.android.internal.util.Preconditions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that allows creation and management of per-app, test-only networks
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@TestApi
|
||||||
|
public class TestNetworkManager {
|
||||||
|
@NonNull private static final String TAG = TestNetworkManager.class.getSimpleName();
|
||||||
|
|
||||||
|
@NonNull private final ITestNetworkManager mService;
|
||||||
|
@NonNull private final Context mContext;
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
public TestNetworkManager(@NonNull Context context, @NonNull ITestNetworkManager service) {
|
||||||
|
mContext = Preconditions.checkNotNull(context, "missing Context");
|
||||||
|
mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Teardown the capability-limited, testing-only network for a given interface
|
||||||
|
*
|
||||||
|
* @param network The test network that should be torn down
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@TestApi
|
||||||
|
public void teardownTestNetwork(@NonNull Network network) {
|
||||||
|
try {
|
||||||
|
mService.teardownTestNetwork(network.netId);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a capability-limited, testing-only network for a given interface
|
||||||
|
*
|
||||||
|
* @param iface the name of the interface to be used for the Network LinkProperties.
|
||||||
|
* @param binder A binder object guarding the lifecycle of this test network.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@TestApi
|
||||||
|
public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
|
||||||
|
try {
|
||||||
|
mService.setupTestNetwork(iface, binder);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a tun interface for testing purposes
|
||||||
|
*
|
||||||
|
* @param linkAddrs an array of LinkAddresses to assign to the TUN interface
|
||||||
|
* @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
|
||||||
|
* TUN interface.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@TestApi
|
||||||
|
public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
|
||||||
|
try {
|
||||||
|
return mService.createTunInterface(linkAddrs);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
338
services/core/java/com/android/server/TestNetworkService.java
Normal file
338
services/core/java/com/android/server/TestNetworkService.java
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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 com.android.internal.util.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.INetd;
|
||||||
|
import android.net.ITestNetworkManager;
|
||||||
|
import android.net.IpPrefix;
|
||||||
|
import android.net.LinkAddress;
|
||||||
|
import android.net.LinkProperties;
|
||||||
|
import android.net.NetworkAgent;
|
||||||
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.NetworkInfo.DetailedState;
|
||||||
|
import android.net.RouteInfo;
|
||||||
|
import android.net.StringNetworkSpecifier;
|
||||||
|
import android.net.TestNetworkInterface;
|
||||||
|
import android.net.util.NetdService;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.HandlerThread;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.INetworkManagementService;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InterfaceAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/** @hide */
|
||||||
|
class TestNetworkService extends ITestNetworkManager.Stub {
|
||||||
|
@NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
|
||||||
|
@NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK";
|
||||||
|
@NonNull private static final String TEST_TUN_PREFIX = "testtun";
|
||||||
|
@NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
|
||||||
|
|
||||||
|
@NonNull private final Context mContext;
|
||||||
|
@NonNull private final INetworkManagementService mNMS;
|
||||||
|
@NonNull private final INetd mNetd;
|
||||||
|
|
||||||
|
@NonNull private final HandlerThread mHandlerThread;
|
||||||
|
@NonNull private final Handler mHandler;
|
||||||
|
|
||||||
|
// Native method stubs
|
||||||
|
private static native int jniCreateTun(@NonNull String iface);
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected TestNetworkService(
|
||||||
|
@NonNull Context context, @NonNull INetworkManagementService netManager) {
|
||||||
|
mHandlerThread = new HandlerThread("TestNetworkServiceThread");
|
||||||
|
mHandlerThread.start();
|
||||||
|
mHandler = new Handler(mHandlerThread.getLooper());
|
||||||
|
|
||||||
|
mContext = checkNotNull(context, "missing Context");
|
||||||
|
mNMS = checkNotNull(netManager, "missing INetworkManagementService");
|
||||||
|
mNetd = checkNotNull(NetdService.getInstance(), "could not get netd instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a TUN interface with the given interface name and link addresses
|
||||||
|
*
|
||||||
|
* <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
|
||||||
|
* TUN interface.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
|
||||||
|
enforceTestNetworkPermissions(mContext);
|
||||||
|
|
||||||
|
checkNotNull(linkAddrs, "missing linkAddrs");
|
||||||
|
|
||||||
|
String iface = TEST_TUN_PREFIX + sTestTunIndex.getAndIncrement();
|
||||||
|
return Binder.withCleanCallingIdentity(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
ParcelFileDescriptor tunIntf =
|
||||||
|
ParcelFileDescriptor.adoptFd(jniCreateTun(iface));
|
||||||
|
for (LinkAddress addr : linkAddrs) {
|
||||||
|
mNetd.interfaceAddAddress(
|
||||||
|
iface,
|
||||||
|
addr.getAddress().getHostAddress(),
|
||||||
|
addr.getPrefixLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TestNetworkInterface(tunIntf, iface);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracker for TestNetworkAgents
|
||||||
|
@GuardedBy("mTestNetworkTracker")
|
||||||
|
@NonNull
|
||||||
|
private final SparseArray<TestNetworkAgent> mTestNetworkTracker = new SparseArray<>();
|
||||||
|
|
||||||
|
public class TestNetworkAgent extends NetworkAgent implements IBinder.DeathRecipient {
|
||||||
|
private static final int NETWORK_SCORE = 1; // Use a low, non-zero score.
|
||||||
|
|
||||||
|
private final int mUid;
|
||||||
|
@NonNull private final NetworkInfo mNi;
|
||||||
|
@NonNull private final NetworkCapabilities mNc;
|
||||||
|
@NonNull private final LinkProperties mLp;
|
||||||
|
|
||||||
|
@GuardedBy("mBinderLock")
|
||||||
|
@NonNull
|
||||||
|
private IBinder mBinder;
|
||||||
|
|
||||||
|
@NonNull private final Object mBinderLock = new Object();
|
||||||
|
|
||||||
|
private TestNetworkAgent(
|
||||||
|
@NonNull Looper looper,
|
||||||
|
@NonNull Context context,
|
||||||
|
@NonNull NetworkInfo ni,
|
||||||
|
@NonNull NetworkCapabilities nc,
|
||||||
|
@NonNull LinkProperties lp,
|
||||||
|
int uid,
|
||||||
|
@NonNull IBinder binder)
|
||||||
|
throws RemoteException {
|
||||||
|
super(looper, context, TEST_NETWORK_TYPE, ni, nc, lp, NETWORK_SCORE);
|
||||||
|
|
||||||
|
mUid = uid;
|
||||||
|
mNi = ni;
|
||||||
|
mNc = nc;
|
||||||
|
mLp = lp;
|
||||||
|
|
||||||
|
synchronized (mBinderLock) {
|
||||||
|
mBinder = binder; // Binder null-checks in create()
|
||||||
|
|
||||||
|
try {
|
||||||
|
mBinder.linkToDeath(this, 0);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
binderDied();
|
||||||
|
throw e; // Abort, signal failure up the stack.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the Binder object dies, this function is called to free the resources of this
|
||||||
|
* TestNetworkAgent
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void binderDied() {
|
||||||
|
teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void unwanted() {
|
||||||
|
teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void teardown() {
|
||||||
|
mNi.setDetailedState(DetailedState.DISCONNECTED, null, null);
|
||||||
|
mNi.setIsAvailable(false);
|
||||||
|
sendNetworkInfo(mNi);
|
||||||
|
|
||||||
|
// Synchronize on mBinderLock to ensure that unlinkToDeath is never called more than
|
||||||
|
// once (otherwise it could throw an exception)
|
||||||
|
synchronized (mBinderLock) {
|
||||||
|
// If mBinder is null, this Test Network has already been cleaned up.
|
||||||
|
if (mBinder == null) return;
|
||||||
|
mBinder.unlinkToDeath(this, 0);
|
||||||
|
mBinder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up
|
||||||
|
// resources, even for binder death or unwanted calls.
|
||||||
|
synchronized (mTestNetworkTracker) {
|
||||||
|
mTestNetworkTracker.remove(netId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestNetworkAgent registerTestNetworkAgent(
|
||||||
|
@NonNull Looper looper,
|
||||||
|
@NonNull Context context,
|
||||||
|
@NonNull String iface,
|
||||||
|
int callingUid,
|
||||||
|
@NonNull IBinder binder)
|
||||||
|
throws RemoteException, SocketException {
|
||||||
|
checkNotNull(looper, "missing Looper");
|
||||||
|
checkNotNull(context, "missing Context");
|
||||||
|
// iface and binder validity checked by caller
|
||||||
|
|
||||||
|
// Build network info with special testing type
|
||||||
|
NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_TEST, 0, TEST_NETWORK_TYPE, "");
|
||||||
|
ni.setDetailedState(DetailedState.CONNECTED, null, null);
|
||||||
|
ni.setIsAvailable(true);
|
||||||
|
|
||||||
|
// Build narrow set of NetworkCapabilities, useful only for testing
|
||||||
|
NetworkCapabilities nc = new NetworkCapabilities();
|
||||||
|
nc.clearAll(); // Remove default capabilities.
|
||||||
|
nc.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
|
||||||
|
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
|
||||||
|
nc.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
|
||||||
|
nc.setNetworkSpecifier(new StringNetworkSpecifier(iface));
|
||||||
|
|
||||||
|
// Build LinkProperties
|
||||||
|
LinkProperties lp = new LinkProperties();
|
||||||
|
lp.setInterfaceName(iface);
|
||||||
|
|
||||||
|
// Find the currently assigned addresses, and add them to LinkProperties
|
||||||
|
boolean allowIPv4 = false, allowIPv6 = false;
|
||||||
|
NetworkInterface netIntf = NetworkInterface.getByName(iface);
|
||||||
|
checkNotNull(netIntf, "No such network interface found: " + netIntf);
|
||||||
|
|
||||||
|
for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) {
|
||||||
|
lp.addLinkAddress(
|
||||||
|
new LinkAddress(intfAddr.getAddress(), intfAddr.getNetworkPrefixLength()));
|
||||||
|
|
||||||
|
if (intfAddr.getAddress() instanceof Inet6Address) {
|
||||||
|
allowIPv6 |= !intfAddr.getAddress().isLinkLocalAddress();
|
||||||
|
} else if (intfAddr.getAddress() instanceof Inet4Address) {
|
||||||
|
allowIPv4 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add global routes (but as non-default, non-internet providing network)
|
||||||
|
if (allowIPv4) {
|
||||||
|
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null, iface));
|
||||||
|
}
|
||||||
|
if (allowIPv6) {
|
||||||
|
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TestNetworkAgent(looper, context, ni, nc, lp, callingUid, binder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up a Network with extremely limited privileges, guarded by the MANAGE_TEST_NETWORKS
|
||||||
|
* permission.
|
||||||
|
*
|
||||||
|
* <p>This method provides a Network that is useful only for testing.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
|
||||||
|
enforceTestNetworkPermissions(mContext);
|
||||||
|
|
||||||
|
checkNotNull(iface, "missing Iface");
|
||||||
|
checkNotNull(binder, "missing IBinder");
|
||||||
|
|
||||||
|
if (!(iface.startsWith(INetd.IPSEC_INTERFACE_PREFIX)
|
||||||
|
|| iface.startsWith(TEST_TUN_PREFIX))) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Cannot create network for non ipsec, non-testtun interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup needs to be done with NETWORK_STACK privileges.
|
||||||
|
int callingUid = Binder.getCallingUid();
|
||||||
|
Binder.withCleanCallingIdentity(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
mNMS.setInterfaceUp(iface);
|
||||||
|
|
||||||
|
// Synchronize all accesses to mTestNetworkTracker to prevent the case
|
||||||
|
// where:
|
||||||
|
// 1. TestNetworkAgent successfully binds to death of binder
|
||||||
|
// 2. Before it is added to the mTestNetworkTracker, binder dies,
|
||||||
|
// binderDied() is called (on a different thread)
|
||||||
|
// 3. This thread is pre-empted, put() is called after remove()
|
||||||
|
synchronized (mTestNetworkTracker) {
|
||||||
|
TestNetworkAgent agent =
|
||||||
|
registerTestNetworkAgent(
|
||||||
|
mHandler.getLooper(),
|
||||||
|
mContext,
|
||||||
|
iface,
|
||||||
|
callingUid,
|
||||||
|
binder);
|
||||||
|
|
||||||
|
mTestNetworkTracker.put(agent.netId, agent);
|
||||||
|
}
|
||||||
|
} catch (SocketException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Teardown a test network */
|
||||||
|
@Override
|
||||||
|
public void teardownTestNetwork(int netId) {
|
||||||
|
enforceTestNetworkPermissions(mContext);
|
||||||
|
|
||||||
|
TestNetworkAgent agent;
|
||||||
|
synchronized (mTestNetworkTracker) {
|
||||||
|
agent = mTestNetworkTracker.get(netId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (agent == null) {
|
||||||
|
return; // Already torn down
|
||||||
|
} else if (agent.mUid != Binder.getCallingUid()) {
|
||||||
|
throw new SecurityException("Attempted to modify other user's test networks");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe to be called multiple times.
|
||||||
|
agent.teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
// STOPSHIP: Change this back to android.Manifest.permission.MANAGE_TEST_NETWORKS
|
||||||
|
private static final String PERMISSION_NAME = "dummy";
|
||||||
|
|
||||||
|
public static void enforceTestNetworkPermissions(@NonNull Context context) {
|
||||||
|
// STOPSHIP: Re-enable these checks. Disabled until adoptShellPermissionIdentity() can be
|
||||||
|
// called from CTS test code.
|
||||||
|
if (false) {
|
||||||
|
context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
107
services/core/jni/com_android_server_TestNetworkService.cpp
Normal file
107
services/core/jni/com_android_server_TestNetworkService.cpp
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOG_NDEBUG 0
|
||||||
|
|
||||||
|
#define LOG_TAG "TestNetworkServiceJni"
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/if.h>
|
||||||
|
#include <linux/if_tun.h>
|
||||||
|
#include <linux/ipv6_route.h>
|
||||||
|
#include <linux/route.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <log/log.h>
|
||||||
|
|
||||||
|
#include "netutils/ifc.h"
|
||||||
|
|
||||||
|
#include "jni.h"
|
||||||
|
#include <android-base/stringprintf.h>
|
||||||
|
#include <android-base/unique_fd.h>
|
||||||
|
#include <nativehelper/JNIHelp.h>
|
||||||
|
#include <nativehelper/ScopedUtfChars.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void throwException(JNIEnv* env, int error, const char* action, const char* iface) {
|
||||||
|
const std::string& msg =
|
||||||
|
android::base::StringPrintf("Error %s %s: %s", action, iface, strerror(error));
|
||||||
|
|
||||||
|
jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
static int createTunInterface(JNIEnv* env, const char* iface) {
|
||||||
|
base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
|
||||||
|
ifreq ifr{};
|
||||||
|
|
||||||
|
// Allocate interface.
|
||||||
|
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
||||||
|
strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
|
||||||
|
if (ioctl(tun.get(), TUNSETIFF, &ifr)) {
|
||||||
|
throwException(env, errno, "allocating", ifr.ifr_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate interface using an unconnected datagram socket.
|
||||||
|
base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
|
||||||
|
ifr.ifr_flags = IFF_UP;
|
||||||
|
|
||||||
|
if (ioctl(inet6CtrlSock.get(), SIOCSIFFLAGS, &ifr)) {
|
||||||
|
throwException(env, errno, "activating", ifr.ifr_name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tun.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static jint create(JNIEnv* env, jobject /* thiz */, jstring jIface) {
|
||||||
|
ScopedUtfChars iface(env, jIface);
|
||||||
|
if (!iface.c_str()) {
|
||||||
|
jniThrowNullPointerException(env, "iface");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tun = createTunInterface(env, iface.c_str());
|
||||||
|
|
||||||
|
// Any exceptions will be thrown from the createTunInterface call
|
||||||
|
return tun;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static const JNINativeMethod gMethods[] = {
|
||||||
|
{"jniCreateTun", "(Ljava/lang/String;)I", (void*)create},
|
||||||
|
};
|
||||||
|
|
||||||
|
int register_android_server_TestNetworkService(JNIEnv* env) {
|
||||||
|
return jniRegisterNativeMethods(env, "com/android/server/TestNetworkService", gMethods,
|
||||||
|
NELEM(gMethods));
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace android
|
||||||
Reference in New Issue
Block a user