diff --git a/framework/src/android/net/VpnManager.java b/framework/src/android/net/VpnManager.java deleted file mode 100644 index f472ed4381..0000000000 --- a/framework/src/android/net/VpnManager.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * 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 static com.android.internal.util.Preconditions.checkNotNull; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.UserIdInt; -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.os.RemoteException; - -import com.android.internal.net.LegacyVpnInfo; -import com.android.internal.net.VpnConfig; -import com.android.internal.net.VpnProfile; - -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.security.GeneralSecurityException; -import java.util.List; - -/** - * This class provides an interface for apps to manage platform VPN profiles - * - *

Apps can use this API to provide profiles with which the platform can set up a VPN without - * further app intermediation. When a VPN profile is present and the app is selected as an always-on - * VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the - * app (unlike VpnService). - * - *

VPN apps using supported protocols should preferentially use this API over the {@link - * VpnService} API for ease-of-development and reduced maintainance burden. This also give the user - * the guarantee that VPN network traffic is not subjected to on-device packet interception. - * - * @see Ikev2VpnProfile - */ -public class VpnManager { - /** Type representing a lack of VPN @hide */ - public static final int TYPE_VPN_NONE = -1; - - /** - * A VPN created by an app using the {@link VpnService} API. - * @hide - */ - public static final int TYPE_VPN_SERVICE = 1; - - /** - * A VPN created using a {@link VpnManager} API such as {@link #startProvisionedVpnProfile}. - * @hide - */ - public static final int TYPE_VPN_PLATFORM = 2; - - /** - * An IPsec VPN created by the built-in LegacyVpnRunner. - * @deprecated new Android devices should use VPN_TYPE_PLATFORM instead. - * @hide - */ - @Deprecated - public static final int TYPE_VPN_LEGACY = 3; - - /** - * Channel for VPN notifications. - * @hide - */ - public static final String NOTIFICATION_CHANNEL_VPN = "VPN"; - - /** @hide */ - @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY}) - @Retention(RetentionPolicy.SOURCE) - public @interface VpnType {} - - @NonNull private final Context mContext; - @NonNull private final IVpnManager mService; - - private static Intent getIntentForConfirmation() { - final Intent intent = new Intent(); - final ComponentName componentName = ComponentName.unflattenFromString( - Resources.getSystem().getString( - com.android.internal.R.string.config_platformVpnConfirmDialogComponent)); - intent.setComponent(componentName); - return intent; - } - - /** - * Create an instance of the VpnManager with the given context. - * - *

Internal only. Applications are expected to obtain an instance of the VpnManager via the - * {@link Context.getSystemService()} method call. - * - * @hide - */ - public VpnManager(@NonNull Context ctx, @NonNull IVpnManager service) { - mContext = checkNotNull(ctx, "missing Context"); - mService = checkNotNull(service, "missing IVpnManager"); - } - - /** - * Install a VpnProfile configuration keyed on the calling app's package name. - * - *

This method returns {@code null} if user consent has already been granted, or an {@link - * Intent} to a system activity. If an intent is returned, the application should launch the - * activity using {@link Activity#startActivityForResult} to request user consent. The activity - * may pop up a dialog to require user action, and the result will come back via its {@link - * Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has - * consented, and the VPN profile can be started. - * - * @param profile the VpnProfile provided by this package. Will override any previous VpnProfile - * stored for this package. - * @return an Intent requesting user consent to start the VPN, or null if consent is not - * required based on privileges or previous user consent. - */ - @Nullable - public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) { - final VpnProfile internalProfile; - - try { - internalProfile = profile.toVpnProfile(); - } catch (GeneralSecurityException | IOException e) { - // Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions - // indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded - // string as required by the VpnProfile. - throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e); - } - - try { - // Profile can never be null; it either gets set, or an exception is thrown. - if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) { - return null; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return getIntentForConfirmation(); - } - - /** - * Delete the VPN profile configuration that was provisioned by the calling app - * - * @throws SecurityException if this would violate user settings - */ - public void deleteProvisionedVpnProfile() { - try { - mService.deleteVpnProfile(mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Request the startup of a previously provisioned VPN. - * - * @throws SecurityException exception if user or device settings prevent this VPN from being - * setup, or if user consent has not been granted - */ - public void startProvisionedVpnProfile() { - try { - mService.startVpnProfile(mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** Tear down the VPN provided by the calling app (if any) */ - public void stopProvisionedVpnProfile() { - try { - mService.stopVpnProfile(mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the VPN configuration for the given user ID. - * @hide - */ - @Nullable - public VpnConfig getVpnConfig(@UserIdInt int userId) { - try { - return mService.getVpnConfig(userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Resets all VPN settings back to factory defaults. - * @hide - */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public void factoryReset() { - try { - mService.factoryReset(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Prepare for a VPN application. - * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId}, - * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required. - * - * @param oldPackage Package name of the application which currently controls VPN, which will - * be replaced. If there is no such application, this should should either be - * {@code null} or {@link VpnConfig.LEGACY_VPN}. - * @param newPackage Package name of the application which should gain control of VPN, or - * {@code null} to disable. - * @param userId User for whom to prepare the new VPN. - * - * @hide - */ - public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage, - int userId) { - try { - return mService.prepareVpn(oldPackage, newPackage, userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Set whether the VPN package has the ability to launch VPNs without user intervention. This - * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn} - * class. If the caller is not {@code userId}, {@link - * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required. - * - * @param packageName The package for which authorization state should change. - * @param userId User for whom {@code packageName} is installed. - * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN - * permissions should be granted. When unauthorizing an app, {@link - * VpnManager.TYPE_VPN_NONE} should be used. - * @hide - */ - public void setVpnPackageAuthorization( - String packageName, int userId, @VpnManager.VpnType int vpnType) { - try { - mService.setVpnPackageAuthorization(packageName, userId, vpnType); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Checks if a VPN app supports always-on mode. - * - * In order to support the always-on feature, an app has to - *

- * - * @param userId The identifier of the user for whom the VPN app is installed. - * @param vpnPackage The canonical package name of the VPN app. - * @return {@code true} if and only if the VPN app exists and supports always-on mode. - * @hide - */ - public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) { - try { - return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Configures an always-on VPN connection through a specific application. - * This connection is automatically granted and persisted after a reboot. - * - *

The designated package should declare a {@link VpnService} in its - * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE}, - * otherwise the call will fail. - * - * @param userId The identifier of the user to set an always-on VPN for. - * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} - * to remove an existing always-on VPN configuration. - * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or - * {@code false} otherwise. - * @param lockdownAllowlist The list of packages that are allowed to access network directly - * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so - * this method must be called when a package that should be allowed is installed or - * uninstalled. - * @return {@code true} if the package is set as always-on VPN controller; - * {@code false} otherwise. - * @hide - */ - @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) - public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage, - boolean lockdownEnabled, @Nullable List lockdownAllowlist) { - try { - return mService.setAlwaysOnVpnPackage( - userId, vpnPackage, lockdownEnabled, lockdownAllowlist); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns the package name of the currently set always-on VPN application. - * If there is no always-on VPN set, or the VPN is provided by the system instead - * of by an app, {@code null} will be returned. - * - * @return Package name of VPN controller responsible for always-on VPN, - * or {@code null} if none is set. - * @hide - */ - @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) - public String getAlwaysOnVpnPackageForUser(int userId) { - try { - return mService.getAlwaysOnVpnPackage(userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @return whether always-on VPN is in lockdown mode. - * - * @hide - **/ - @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) - public boolean isVpnLockdownEnabled(int userId) { - try { - return mService.isVpnLockdownEnabled(userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @return the list of packages that are allowed to access network when always-on VPN is in - * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active. - * - * @hide - **/ - @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) - public List getVpnLockdownAllowlist(int userId) { - try { - return mService.getVpnLockdownAllowlist(userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the legacy VPN information for the specified user ID. - * @hide - */ - public LegacyVpnInfo getLegacyVpnInfo(@UserIdInt int userId) { - try { - return mService.getLegacyVpnInfo(userId); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Starts a legacy VPN. - * @hide - */ - public void startLegacyVpn(VpnProfile profile) { - try { - mService.startLegacyVpn(profile); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Informs the service that legacy lockdown VPN state should be updated (e.g., if its keystore - * entry has been updated). If the LockdownVpn mechanism is enabled, updates the vpn - * with a reload of its profile. - * - *

This method can only be called by the system UID - * @return a boolean indicating success - * - * @hide - */ - public boolean updateLockdownVpn() { - try { - return mService.updateLockdownVpn(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } -} \ No newline at end of file diff --git a/framework/src/android/net/VpnService.java b/framework/src/android/net/VpnService.java deleted file mode 100644 index e43b0b6fa6..0000000000 --- a/framework/src/android/net/VpnService.java +++ /dev/null @@ -1,902 +0,0 @@ -/* - * Copyright (C) 2011 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 static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.app.Activity; -import android.app.PendingIntent; -import android.app.Service; -import android.app.admin.DevicePolicyManager; -import android.compat.annotation.UnsupportedAppUsage; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.IBinder; -import android.os.Parcel; -import android.os.ParcelFileDescriptor; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.UserHandle; - -import com.android.internal.net.VpnConfig; - -import java.net.DatagramSocket; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.Socket; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * VpnService is a base class for applications to extend and build their - * own VPN solutions. In general, it creates a virtual network interface, - * configures addresses and routing rules, and returns a file descriptor - * to the application. Each read from the descriptor retrieves an outgoing - * packet which was routed to the interface. Each write to the descriptor - * injects an incoming packet just like it was received from the interface. - * The interface is running on Internet Protocol (IP), so packets are - * always started with IP headers. The application then completes a VPN - * connection by processing and exchanging packets with the remote server - * over a tunnel. - * - *

Letting applications intercept packets raises huge security concerns. - * A VPN application can easily break the network. Besides, two of them may - * conflict with each other. The system takes several actions to address - * these issues. Here are some key points: - *

- * - *

There are two primary methods in this class: {@link #prepare} and - * {@link Builder#establish}. The former deals with user action and stops - * the VPN connection created by another application. The latter creates - * a VPN interface using the parameters supplied to the {@link Builder}. - * An application must call {@link #prepare} to grant the right to use - * other methods in this class, and the right can be revoked at any time. - * Here are the general steps to create a VPN connection: - *

    - *
  1. When the user presses the button to connect, call {@link #prepare} - * and launch the returned intent, if non-null.
  2. - *
  3. When the application becomes prepared, start the service.
  4. - *
  5. Create a tunnel to the remote server and negotiate the network - * parameters for the VPN connection.
  6. - *
  7. Supply those parameters to a {@link Builder} and create a VPN - * interface by calling {@link Builder#establish}.
  8. - *
  9. Process and exchange packets between the tunnel and the returned - * file descriptor.
  10. - *
  11. When {@link #onRevoke} is invoked, close the file descriptor and - * shut down the tunnel gracefully.
  12. - *
- * - *

Services extending this class need to be declared with an appropriate - * permission and intent filter. Their access must be secured by - * {@link android.Manifest.permission#BIND_VPN_SERVICE} permission, and - * their intent filter must match {@link #SERVICE_INTERFACE} action. Here - * is an example of declaring a VPN service in {@code AndroidManifest.xml}: - *

- * <service android:name=".ExampleVpnService"
- *         android:permission="android.permission.BIND_VPN_SERVICE">
- *     <intent-filter>
- *         <action android:name="android.net.VpnService"/>
- *     </intent-filter>
- * </service>
- * - *

The Android system starts a VPN in the background by calling - * {@link android.content.Context#startService startService()}. In Android 8.0 - * (API level 26) and higher, the system places VPN apps on the temporary - * allowlist for a short period so the app can start in the background. The VPN - * app must promote itself to the foreground after it's launched or the system - * will shut down the app. - * - *

Developer's guide

- * - *

To learn more about developing VPN apps, read the - * VPN developer's guide. - * - * @see Builder - */ -public class VpnService extends Service { - - /** - * The action must be matched by the intent filter of this service. It also - * needs to require {@link android.Manifest.permission#BIND_VPN_SERVICE} - * permission so that other applications cannot abuse it. - */ - public static final String SERVICE_INTERFACE = VpnConfig.SERVICE_INTERFACE; - - /** - * Key for boolean meta-data field indicating whether this VpnService supports always-on mode. - * - *

For a VPN app targeting {@link android.os.Build.VERSION_CODES#N API 24} or above, Android - * provides users with the ability to set it as always-on, so that VPN connection is - * persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device - * owner and profile owner apps through - * {@link DevicePolicyManager#setAlwaysOnVpnPackage}. - * - *

VPN apps not supporting this feature should opt out by adding this meta-data field to the - * {@code VpnService} component of {@code AndroidManifest.xml}. In case there is more than one - * {@code VpnService} component defined in {@code AndroidManifest.xml}, opting out any one of - * them will opt out the entire app. For example, - *

 {@code
-     * 
-     *     
-     *         
-     *     
-     *     
-     * 
-     * } 
- * - *

This meta-data field defaults to {@code true} if absent. It will only have effect on - * {@link android.os.Build.VERSION_CODES#O_MR1} or higher. - */ - public static final String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON = - "android.net.VpnService.SUPPORTS_ALWAYS_ON"; - - /** - * Use IVpnManager since those methods are hidden and not available in VpnManager. - */ - private static IVpnManager getService() { - return IVpnManager.Stub.asInterface( - ServiceManager.getService(Context.VPN_MANAGEMENT_SERVICE)); - } - - /** - * Prepare to establish a VPN connection. This method returns {@code null} - * if the VPN application is already prepared or if the user has previously - * consented to the VPN application. Otherwise, it returns an - * {@link Intent} to a system activity. The application should launch the - * activity using {@link Activity#startActivityForResult} to get itself - * prepared. The activity may pop up a dialog to require user action, and - * the result will come back via its {@link Activity#onActivityResult}. - * If the result is {@link Activity#RESULT_OK}, the application becomes - * prepared and is granted to use other methods in this class. - * - *

Only one application can be granted at the same time. The right - * is revoked when another application is granted. The application - * losing the right will be notified via its {@link #onRevoke}. Unless - * it becomes prepared again, subsequent calls to other methods in this - * class will fail. - * - *

The user may disable the VPN at any time while it is activated, in - * which case this method will return an intent the next time it is - * executed to obtain the user's consent again. - * - * @see #onRevoke - */ - public static Intent prepare(Context context) { - try { - if (getService().prepareVpn(context.getPackageName(), null, context.getUserId())) { - return null; - } - } catch (RemoteException e) { - // ignore - } - return VpnConfig.getIntentForConfirmation(); - } - - /** - * Version of {@link #prepare(Context)} which does not require user consent. - * - *

Requires {@link android.Manifest.permission#CONTROL_VPN} and should generally not be - * used. Only acceptable in situations where user consent has been obtained through other means. - * - *

Once this is run, future preparations may be done with the standard prepare method as this - * will authorize the package to prepare the VPN without consent in the future. - * - * @hide - */ - @SystemApi - @RequiresPermission(android.Manifest.permission.CONTROL_VPN) - public static void prepareAndAuthorize(Context context) { - IVpnManager vm = getService(); - String packageName = context.getPackageName(); - try { - // Only prepare if we're not already prepared. - int userId = context.getUserId(); - if (!vm.prepareVpn(packageName, null, userId)) { - vm.prepareVpn(null, packageName, userId); - } - vm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE); - } catch (RemoteException e) { - // ignore - } - } - - /** - * Protect a socket from VPN connections. After protecting, data sent - * through this socket will go directly to the underlying network, - * so its traffic will not be forwarded through the VPN. - * This method is useful if some connections need to be kept - * outside of VPN. For example, a VPN tunnel should protect itself if its - * destination is covered by VPN routes. Otherwise its outgoing packets - * will be sent back to the VPN interface and cause an infinite loop. This - * method will fail if the application is not prepared or is revoked. - * - *

The socket is NOT closed by this method. - * - * @return {@code true} on success. - */ - public boolean protect(int socket) { - return NetworkUtils.protectFromVpn(socket); - } - - /** - * Convenience method to protect a {@link Socket} from VPN connections. - * - * @return {@code true} on success. - * @see #protect(int) - */ - public boolean protect(Socket socket) { - return protect(socket.getFileDescriptor$().getInt$()); - } - - /** - * Convenience method to protect a {@link DatagramSocket} from VPN - * connections. - * - * @return {@code true} on success. - * @see #protect(int) - */ - public boolean protect(DatagramSocket socket) { - return protect(socket.getFileDescriptor$().getInt$()); - } - - /** - * Adds a network address to the VPN interface. - * - * Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the - * address is already in use or cannot be assigned to the interface for any other reason. - * - * Adding an address implicitly allows traffic from that address family (i.e., IPv4 or IPv6) to - * be routed over the VPN. @see Builder#allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - * - * @param address The IP address (IPv4 or IPv6) to assign to the VPN interface. - * @param prefixLength The prefix length of the address. - * - * @return {@code true} on success. - * @see Builder#addAddress - * - * @hide - */ - public boolean addAddress(InetAddress address, int prefixLength) { - check(address, prefixLength); - try { - return getService().addVpnAddress(address.getHostAddress(), prefixLength); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - - /** - * Removes a network address from the VPN interface. - * - * Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the - * address is not assigned to the VPN interface, or if it is the only address assigned (thus - * cannot be removed), or if the address cannot be removed for any other reason. - * - * After removing an address, if there are no addresses, routes or DNS servers of a particular - * address family (i.e., IPv4 or IPv6) configured on the VPN, that DOES NOT block that - * family from being routed. In other words, once an address family has been allowed, it stays - * allowed for the rest of the VPN's session. @see Builder#allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - * - * @param address The IP address (IPv4 or IPv6) to assign to the VPN interface. - * @param prefixLength The prefix length of the address. - * - * @return {@code true} on success. - * - * @hide - */ - public boolean removeAddress(InetAddress address, int prefixLength) { - check(address, prefixLength); - try { - return getService().removeVpnAddress(address.getHostAddress(), prefixLength); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - - /** - * Sets the underlying networks used by the VPN for its upstream connections. - * - *

Used by the system to know the actual networks that carry traffic for apps affected by - * this VPN in order to present this information to the user (e.g., via status bar icons). - * - *

This method only needs to be called if the VPN has explicitly bound its underlying - * communications channels — such as the socket(s) passed to {@link #protect(int)} — - * to a {@code Network} using APIs such as {@link Network#bindSocket(Socket)} or - * {@link Network#bindSocket(DatagramSocket)}. The VPN should call this method every time - * the set of {@code Network}s it is using changes. - * - *

{@code networks} is one of the following: - *

- * - *

This call will succeed only if the VPN is currently established. For setting this value - * when the VPN has not yet been established, see {@link Builder#setUnderlyingNetworks}. - * - * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers. - * - * @return {@code true} on success. - */ - public boolean setUnderlyingNetworks(Network[] networks) { - try { - return getService().setUnderlyingNetworksForVpn(networks); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - - /** - * Returns whether the service is running in always-on VPN mode. In this mode the system ensures - * that the service is always running by restarting it when necessary, e.g. after reboot. - * - * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set) - */ - public final boolean isAlwaysOn() { - try { - return getService().isCallerCurrentAlwaysOnVpnApp(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Returns whether the service is running in always-on VPN lockdown mode. In this mode the - * system ensures that the service is always running and that the apps aren't allowed to bypass - * the VPN. - * - * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set) - */ - public final boolean isLockdownEnabled() { - try { - return getService().isCallerCurrentAlwaysOnVpnLockdownApp(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Return the communication interface to the service. This method returns - * {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE} - * action. Applications overriding this method must identify the intent - * and return the corresponding interface accordingly. - * - * @see Service#onBind - */ - @Override - public IBinder onBind(Intent intent) { - if (intent != null && SERVICE_INTERFACE.equals(intent.getAction())) { - return new Callback(); - } - return null; - } - - /** - * Invoked when the application is revoked. At this moment, the VPN - * interface is already deactivated by the system. The application should - * close the file descriptor and shut down gracefully. The default - * implementation of this method is calling {@link Service#stopSelf()}. - * - *

Calls to this method may not happen on the main thread - * of the process. - * - * @see #prepare - */ - public void onRevoke() { - stopSelf(); - } - - /** - * Use raw Binder instead of AIDL since now there is only one usage. - */ - private class Callback extends Binder { - @Override - protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) { - if (code == IBinder.LAST_CALL_TRANSACTION) { - onRevoke(); - return true; - } - return false; - } - } - - /** - * Private method to validate address and prefixLength. - */ - private static void check(InetAddress address, int prefixLength) { - if (address.isLoopbackAddress()) { - throw new IllegalArgumentException("Bad address"); - } - if (address instanceof Inet4Address) { - if (prefixLength < 0 || prefixLength > 32) { - throw new IllegalArgumentException("Bad prefixLength"); - } - } else if (address instanceof Inet6Address) { - if (prefixLength < 0 || prefixLength > 128) { - throw new IllegalArgumentException("Bad prefixLength"); - } - } else { - throw new IllegalArgumentException("Unsupported family"); - } - } - - /** - * Helper class to create a VPN interface. This class should be always - * used within the scope of the outer {@link VpnService}. - * - * @see VpnService - */ - public class Builder { - - private final VpnConfig mConfig = new VpnConfig(); - @UnsupportedAppUsage - private final List mAddresses = new ArrayList(); - @UnsupportedAppUsage - private final List mRoutes = new ArrayList(); - - public Builder() { - mConfig.user = VpnService.this.getClass().getName(); - } - - /** - * Set the name of this session. It will be displayed in - * system-managed dialogs and notifications. This is recommended - * not required. - */ - @NonNull - public Builder setSession(@NonNull String session) { - mConfig.session = session; - return this; - } - - /** - * Set the {@link PendingIntent} to an activity for users to - * configure the VPN connection. If it is not set, the button - * to configure will not be shown in system-managed dialogs. - */ - @NonNull - public Builder setConfigureIntent(@NonNull PendingIntent intent) { - mConfig.configureIntent = intent; - return this; - } - - /** - * Set the maximum transmission unit (MTU) of the VPN interface. If - * it is not set, the default value in the operating system will be - * used. - * - * @throws IllegalArgumentException if the value is not positive. - */ - @NonNull - public Builder setMtu(int mtu) { - if (mtu <= 0) { - throw new IllegalArgumentException("Bad mtu"); - } - mConfig.mtu = mtu; - return this; - } - - /** - * Sets an HTTP proxy for the VPN network. This proxy is only a recommendation - * and it is possible that some apps will ignore it. - */ - @NonNull - public Builder setHttpProxy(@NonNull ProxyInfo proxyInfo) { - mConfig.proxyInfo = proxyInfo; - return this; - } - - /** - * Add a network address to the VPN interface. Both IPv4 and IPv6 - * addresses are supported. At least one address must be set before - * calling {@link #establish}. - * - * Adding an address implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - */ - @NonNull - public Builder addAddress(@NonNull InetAddress address, int prefixLength) { - check(address, prefixLength); - - if (address.isAnyLocalAddress()) { - throw new IllegalArgumentException("Bad address"); - } - mAddresses.add(new LinkAddress(address, prefixLength)); - mConfig.updateAllowedFamilies(address); - return this; - } - - /** - * Convenience method to add a network address to the VPN interface - * using a numeric address string. See {@link InetAddress} for the - * definitions of numeric address formats. - * - * Adding an address implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - * @see #addAddress(InetAddress, int) - */ - @NonNull - public Builder addAddress(@NonNull String address, int prefixLength) { - return addAddress(InetAddress.parseNumericAddress(address), prefixLength); - } - - /** - * Add a network route to the VPN interface. Both IPv4 and IPv6 - * routes are supported. - * - * Adding a route implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the route is invalid. - */ - @NonNull - public Builder addRoute(@NonNull InetAddress address, int prefixLength) { - check(address, prefixLength); - - int offset = prefixLength / 8; - byte[] bytes = address.getAddress(); - if (offset < bytes.length) { - for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) { - if (bytes[offset] != 0) { - throw new IllegalArgumentException("Bad address"); - } - } - } - mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null)); - mConfig.updateAllowedFamilies(address); - return this; - } - - /** - * Convenience method to add a network route to the VPN interface - * using a numeric address string. See {@link InetAddress} for the - * definitions of numeric address formats. - * - * Adding a route implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the route is invalid. - * @see #addRoute(InetAddress, int) - */ - @NonNull - public Builder addRoute(@NonNull String address, int prefixLength) { - return addRoute(InetAddress.parseNumericAddress(address), prefixLength); - } - - /** - * Add a DNS server to the VPN connection. Both IPv4 and IPv6 - * addresses are supported. If none is set, the DNS servers of - * the default network will be used. - * - * Adding a server implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - */ - @NonNull - public Builder addDnsServer(@NonNull InetAddress address) { - if (address.isLoopbackAddress() || address.isAnyLocalAddress()) { - throw new IllegalArgumentException("Bad address"); - } - if (mConfig.dnsServers == null) { - mConfig.dnsServers = new ArrayList(); - } - mConfig.dnsServers.add(address.getHostAddress()); - return this; - } - - /** - * Convenience method to add a DNS server to the VPN connection - * using a numeric address string. See {@link InetAddress} for the - * definitions of numeric address formats. - * - * Adding a server implicitly allows traffic from that address family - * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily - * - * @throws IllegalArgumentException if the address is invalid. - * @see #addDnsServer(InetAddress) - */ - @NonNull - public Builder addDnsServer(@NonNull String address) { - return addDnsServer(InetAddress.parseNumericAddress(address)); - } - - /** - * Add a search domain to the DNS resolver. - */ - @NonNull - public Builder addSearchDomain(@NonNull String domain) { - if (mConfig.searchDomains == null) { - mConfig.searchDomains = new ArrayList(); - } - mConfig.searchDomains.add(domain); - return this; - } - - /** - * Allows traffic from the specified address family. - * - * By default, if no address, route or DNS server of a specific family (IPv4 or IPv6) is - * added to this VPN, then all outgoing traffic of that family is blocked. If any address, - * route or DNS server is added, that family is allowed. - * - * This method allows an address family to be unblocked even without adding an address, - * route or DNS server of that family. Traffic of that family will then typically - * fall-through to the underlying network if it's supported. - * - * {@code family} must be either {@code AF_INET} (for IPv4) or {@code AF_INET6} (for IPv6). - * {@link IllegalArgumentException} is thrown if it's neither. - * - * @param family The address family ({@code AF_INET} or {@code AF_INET6}) to allow. - * - * @return this {@link Builder} object to facilitate chaining of method calls. - */ - @NonNull - public Builder allowFamily(int family) { - if (family == AF_INET) { - mConfig.allowIPv4 = true; - } else if (family == AF_INET6) { - mConfig.allowIPv6 = true; - } else { - throw new IllegalArgumentException(family + " is neither " + AF_INET + " nor " + - AF_INET6); - } - return this; - } - - private void verifyApp(String packageName) throws PackageManager.NameNotFoundException { - IPackageManager pm = IPackageManager.Stub.asInterface( - ServiceManager.getService("package")); - try { - pm.getApplicationInfo(packageName, 0, UserHandle.getCallingUserId()); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - - /** - * Adds an application that's allowed to access the VPN connection. - * - * If this method is called at least once, only applications added through this method (and - * no others) are allowed access. Else (if this method is never called), all applications - * are allowed by default. If some applications are added, other, un-added applications - * will use networking as if the VPN wasn't running. - * - * A {@link Builder} may have only a set of allowed applications OR a set of disallowed - * ones, but not both. Calling this method after {@link #addDisallowedApplication} has - * already been called, or vice versa, will throw an {@link UnsupportedOperationException}. - * - * {@code packageName} must be the canonical name of a currently installed application. - * {@link PackageManager.NameNotFoundException} is thrown if there's no such application. - * - * @throws PackageManager.NameNotFoundException If the application isn't installed. - * - * @param packageName The full name (e.g.: "com.google.apps.contacts") of an application. - * - * @return this {@link Builder} object to facilitate chaining method calls. - */ - @NonNull - public Builder addAllowedApplication(@NonNull String packageName) - throws PackageManager.NameNotFoundException { - if (mConfig.disallowedApplications != null) { - throw new UnsupportedOperationException("addDisallowedApplication already called"); - } - verifyApp(packageName); - if (mConfig.allowedApplications == null) { - mConfig.allowedApplications = new ArrayList(); - } - mConfig.allowedApplications.add(packageName); - return this; - } - - /** - * Adds an application that's denied access to the VPN connection. - * - * By default, all applications are allowed access, except for those denied through this - * method. Denied applications will use networking as if the VPN wasn't running. - * - * A {@link Builder} may have only a set of allowed applications OR a set of disallowed - * ones, but not both. Calling this method after {@link #addAllowedApplication} has already - * been called, or vice versa, will throw an {@link UnsupportedOperationException}. - * - * {@code packageName} must be the canonical name of a currently installed application. - * {@link PackageManager.NameNotFoundException} is thrown if there's no such application. - * - * @throws PackageManager.NameNotFoundException If the application isn't installed. - * - * @param packageName The full name (e.g.: "com.google.apps.contacts") of an application. - * - * @return this {@link Builder} object to facilitate chaining method calls. - */ - @NonNull - public Builder addDisallowedApplication(@NonNull String packageName) - throws PackageManager.NameNotFoundException { - if (mConfig.allowedApplications != null) { - throw new UnsupportedOperationException("addAllowedApplication already called"); - } - verifyApp(packageName); - if (mConfig.disallowedApplications == null) { - mConfig.disallowedApplications = new ArrayList(); - } - mConfig.disallowedApplications.add(packageName); - return this; - } - - /** - * Allows all apps to bypass this VPN connection. - * - * By default, all traffic from apps is forwarded through the VPN interface and it is not - * possible for apps to side-step the VPN. If this method is called, apps may use methods - * such as {@link ConnectivityManager#bindProcessToNetwork} to instead send/receive - * directly over the underlying network or any other network they have permissions for. - * - * @return this {@link Builder} object to facilitate chaining of method calls. - */ - @NonNull - public Builder allowBypass() { - mConfig.allowBypass = true; - return this; - } - - /** - * Sets the VPN interface's file descriptor to be in blocking/non-blocking mode. - * - * By default, the file descriptor returned by {@link #establish} is non-blocking. - * - * @param blocking True to put the descriptor into blocking mode; false for non-blocking. - * - * @return this {@link Builder} object to facilitate chaining method calls. - */ - @NonNull - public Builder setBlocking(boolean blocking) { - mConfig.blocking = blocking; - return this; - } - - /** - * Sets the underlying networks used by the VPN for its upstream connections. - * - * @see VpnService#setUnderlyingNetworks - * - * @param networks An array of networks the VPN uses to tunnel traffic to/from its servers. - * - * @return this {@link Builder} object to facilitate chaining method calls. - */ - @NonNull - public Builder setUnderlyingNetworks(@Nullable Network[] networks) { - mConfig.underlyingNetworks = networks != null ? networks.clone() : null; - return this; - } - - /** - * Marks the VPN network as metered. A VPN network is classified as metered when the user is - * sensitive to heavy data usage due to monetary costs and/or data limitations. In such - * cases, you should set this to {@code true} so that apps on the system can avoid doing - * large data transfers. Otherwise, set this to {@code false}. Doing so would cause VPN - * network to inherit its meteredness from its underlying networks. - * - *

VPN apps targeting {@link android.os.Build.VERSION_CODES#Q} or above will be - * considered metered by default. - * - * @param isMetered {@code true} if VPN network should be treated as metered regardless of - * underlying network meteredness - * @return this {@link Builder} object to facilitate chaining method calls - * @see #setUnderlyingNetworks(Network[]) - * @see ConnectivityManager#isActiveNetworkMetered() - */ - @NonNull - public Builder setMetered(boolean isMetered) { - mConfig.isMetered = isMetered; - return this; - } - - /** - * Create a VPN interface using the parameters supplied to this - * builder. The interface works on IP packets, and a file descriptor - * is returned for the application to access them. Each read - * retrieves an outgoing packet which was routed to the interface. - * Each write injects an incoming packet just like it was received - * from the interface. The file descriptor is put into non-blocking - * mode by default to avoid blocking Java threads. To use the file - * descriptor completely in native space, see - * {@link ParcelFileDescriptor#detachFd()}. The application MUST - * close the file descriptor when the VPN connection is terminated. - * The VPN interface will be removed and the network will be - * restored by the system automatically. - * - *

To avoid conflicts, there can be only one active VPN interface - * at the same time. Usually network parameters are never changed - * during the lifetime of a VPN connection. It is also common for an - * application to create a new file descriptor after closing the - * previous one. However, it is rare but not impossible to have two - * interfaces while performing a seamless handover. In this case, the - * old interface will be deactivated when the new one is created - * successfully. Both file descriptors are valid but now outgoing - * packets will be routed to the new interface. Therefore, after - * draining the old file descriptor, the application MUST close it - * and start using the new file descriptor. If the new interface - * cannot be created, the existing interface and its file descriptor - * remain untouched. - * - *

An exception will be thrown if the interface cannot be created - * for any reason. However, this method returns {@code null} if the - * application is not prepared or is revoked. This helps solve - * possible race conditions between other VPN applications. - * - * @return {@link ParcelFileDescriptor} of the VPN interface, or - * {@code null} if the application is not prepared. - * @throws IllegalArgumentException if a parameter is not accepted - * by the operating system. - * @throws IllegalStateException if a parameter cannot be applied - * by the operating system. - * @throws SecurityException if the service is not properly declared - * in {@code AndroidManifest.xml}. - * @see VpnService - */ - @Nullable - public ParcelFileDescriptor establish() { - mConfig.addresses = mAddresses; - mConfig.routes = mRoutes; - - try { - return getService().establishVpn(mConfig); - } catch (RemoteException e) { - throw new IllegalStateException(e); - } - } - } -} diff --git a/service/Android.bp b/service/Android.bp index 8fc3181807..ed1716fad8 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -25,7 +25,6 @@ cc_library_shared { ], srcs: [ "jni/com_android_server_TestNetworkService.cpp", - "jni/com_android_server_connectivity_Vpn.cpp", "jni/onload.cpp", ], shared_libs: [ diff --git a/service/jni/com_android_server_connectivity_Vpn.cpp b/service/jni/com_android_server_connectivity_Vpn.cpp deleted file mode 100644 index ea5e7183c9..0000000000 --- a/service/jni/com_android_server_connectivity_Vpn.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright (C) 2011 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 "VpnJni" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "netutils/ifc.h" - -#include "jni.h" -#include - -namespace android -{ - -static int inet4 = -1; -static int inet6 = -1; - -static inline in_addr_t *as_in_addr(sockaddr *sa) { - return &((sockaddr_in *)sa)->sin_addr.s_addr; -} - -//------------------------------------------------------------------------------ - -#define SYSTEM_ERROR (-1) -#define BAD_ARGUMENT (-2) - -static int create_interface(int mtu) -{ - int tun = open("/dev/tun", O_RDWR | O_NONBLOCK | O_CLOEXEC); - - ifreq ifr4; - memset(&ifr4, 0, sizeof(ifr4)); - - // Allocate interface. - ifr4.ifr_flags = IFF_TUN | IFF_NO_PI; - if (ioctl(tun, TUNSETIFF, &ifr4)) { - ALOGE("Cannot allocate TUN: %s", strerror(errno)); - goto error; - } - - // Activate interface. - ifr4.ifr_flags = IFF_UP; - if (ioctl(inet4, SIOCSIFFLAGS, &ifr4)) { - ALOGE("Cannot activate %s: %s", ifr4.ifr_name, strerror(errno)); - goto error; - } - - // Set MTU if it is specified. - ifr4.ifr_mtu = mtu; - if (mtu > 0 && ioctl(inet4, SIOCSIFMTU, &ifr4)) { - ALOGE("Cannot set MTU on %s: %s", ifr4.ifr_name, strerror(errno)); - goto error; - } - - return tun; - -error: - close(tun); - return SYSTEM_ERROR; -} - -static int get_interface_name(char *name, int tun) -{ - ifreq ifr4; - if (ioctl(tun, TUNGETIFF, &ifr4)) { - ALOGE("Cannot get interface name: %s", strerror(errno)); - return SYSTEM_ERROR; - } - strncpy(name, ifr4.ifr_name, IFNAMSIZ); - return 0; -} - -static int get_interface_index(const char *name) -{ - ifreq ifr4; - strncpy(ifr4.ifr_name, name, IFNAMSIZ); - if (ioctl(inet4, SIOGIFINDEX, &ifr4)) { - ALOGE("Cannot get index of %s: %s", name, strerror(errno)); - return SYSTEM_ERROR; - } - return ifr4.ifr_ifindex; -} - -static int set_addresses(const char *name, const char *addresses) -{ - int index = get_interface_index(name); - if (index < 0) { - return index; - } - - ifreq ifr4; - memset(&ifr4, 0, sizeof(ifr4)); - strncpy(ifr4.ifr_name, name, IFNAMSIZ); - ifr4.ifr_addr.sa_family = AF_INET; - ifr4.ifr_netmask.sa_family = AF_INET; - - in6_ifreq ifr6; - memset(&ifr6, 0, sizeof(ifr6)); - ifr6.ifr6_ifindex = index; - - char address[65]; - int prefix; - int chars; - int count = 0; - - while (sscanf(addresses, " %64[^/]/%d %n", address, &prefix, &chars) == 2) { - addresses += chars; - - if (strchr(address, ':')) { - // Add an IPv6 address. - if (inet_pton(AF_INET6, address, &ifr6.ifr6_addr) != 1 || - prefix < 0 || prefix > 128) { - count = BAD_ARGUMENT; - break; - } - - ifr6.ifr6_prefixlen = prefix; - if (ioctl(inet6, SIOCSIFADDR, &ifr6)) { - count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; - break; - } - } else { - // Add an IPv4 address. - if (inet_pton(AF_INET, address, as_in_addr(&ifr4.ifr_addr)) != 1 || - prefix < 0 || prefix > 32) { - count = BAD_ARGUMENT; - break; - } - - if (count) { - snprintf(ifr4.ifr_name, sizeof(ifr4.ifr_name), "%s:%d", name, count); - } - if (ioctl(inet4, SIOCSIFADDR, &ifr4)) { - count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; - break; - } - - in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0; - *as_in_addr(&ifr4.ifr_netmask) = htonl(mask); - if (ioctl(inet4, SIOCSIFNETMASK, &ifr4)) { - count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR; - break; - } - } - ALOGD("Address added on %s: %s/%d", name, address, prefix); - ++count; - } - - if (count == BAD_ARGUMENT) { - ALOGE("Invalid address: %s/%d", address, prefix); - } else if (count == SYSTEM_ERROR) { - ALOGE("Cannot add address: %s/%d: %s", address, prefix, strerror(errno)); - } else if (*addresses) { - ALOGE("Invalid address: %s", addresses); - count = BAD_ARGUMENT; - } - - return count; -} - -static int reset_interface(const char *name) -{ - ifreq ifr4; - strncpy(ifr4.ifr_name, name, IFNAMSIZ); - ifr4.ifr_flags = 0; - - if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) { - ALOGE("Cannot reset %s: %s", name, strerror(errno)); - return SYSTEM_ERROR; - } - return 0; -} - -static int check_interface(const char *name) -{ - ifreq ifr4; - strncpy(ifr4.ifr_name, name, IFNAMSIZ); - ifr4.ifr_flags = 0; - - if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) { - ALOGE("Cannot check %s: %s", name, strerror(errno)); - } - return ifr4.ifr_flags; -} - -static bool modifyAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress, - jint jPrefixLength, bool add) -{ - int error = SYSTEM_ERROR; - const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; - const char *address = jAddress ? env->GetStringUTFChars(jAddress, NULL) : NULL; - - if (!name) { - jniThrowNullPointerException(env, "name"); - } else if (!address) { - jniThrowNullPointerException(env, "address"); - } else { - if (add) { - if ((error = ifc_add_address(name, address, jPrefixLength)) != 0) { - ALOGE("Cannot add address %s/%d on interface %s (%s)", address, jPrefixLength, name, - strerror(-error)); - } - } else { - if ((error = ifc_del_address(name, address, jPrefixLength)) != 0) { - ALOGE("Cannot del address %s/%d on interface %s (%s)", address, jPrefixLength, name, - strerror(-error)); - } - } - } - - if (name) { - env->ReleaseStringUTFChars(jName, name); - } - if (address) { - env->ReleaseStringUTFChars(jAddress, address); - } - return !error; -} - -//------------------------------------------------------------------------------ - -static void throwException(JNIEnv *env, int error, const char *message) -{ - if (error == SYSTEM_ERROR) { - jniThrowException(env, "java/lang/IllegalStateException", message); - } else { - jniThrowException(env, "java/lang/IllegalArgumentException", message); - } -} - -static jint create(JNIEnv *env, jobject /* thiz */, jint mtu) -{ - int tun = create_interface(mtu); - if (tun < 0) { - throwException(env, tun, "Cannot create interface"); - return -1; - } - return tun; -} - -static jstring getName(JNIEnv *env, jobject /* thiz */, jint tun) -{ - char name[IFNAMSIZ]; - if (get_interface_name(name, tun) < 0) { - throwException(env, SYSTEM_ERROR, "Cannot get interface name"); - return NULL; - } - return env->NewStringUTF(name); -} - -static jint setAddresses(JNIEnv *env, jobject /* thiz */, jstring jName, - jstring jAddresses) -{ - const char *name = NULL; - const char *addresses = NULL; - int count = -1; - - name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; - if (!name) { - jniThrowNullPointerException(env, "name"); - goto error; - } - addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL; - if (!addresses) { - jniThrowNullPointerException(env, "addresses"); - goto error; - } - count = set_addresses(name, addresses); - if (count < 0) { - throwException(env, count, "Cannot set address"); - count = -1; - } - -error: - if (name) { - env->ReleaseStringUTFChars(jName, name); - } - if (addresses) { - env->ReleaseStringUTFChars(jAddresses, addresses); - } - return count; -} - -static void reset(JNIEnv *env, jobject /* thiz */, jstring jName) -{ - const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; - if (!name) { - jniThrowNullPointerException(env, "name"); - return; - } - if (reset_interface(name) < 0) { - throwException(env, SYSTEM_ERROR, "Cannot reset interface"); - } - env->ReleaseStringUTFChars(jName, name); -} - -static jint check(JNIEnv *env, jobject /* thiz */, jstring jName) -{ - const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL; - if (!name) { - jniThrowNullPointerException(env, "name"); - return 0; - } - int flags = check_interface(name); - env->ReleaseStringUTFChars(jName, name); - return flags; -} - -static bool addAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress, - jint jPrefixLength) -{ - return modifyAddress(env, thiz, jName, jAddress, jPrefixLength, true); -} - -static bool delAddress(JNIEnv *env, jobject thiz, jstring jName, jstring jAddress, - jint jPrefixLength) -{ - return modifyAddress(env, thiz, jName, jAddress, jPrefixLength, false); -} - -//------------------------------------------------------------------------------ - -static const JNINativeMethod gMethods[] = { - {"jniCreate", "(I)I", (void *)create}, - {"jniGetName", "(I)Ljava/lang/String;", (void *)getName}, - {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses}, - {"jniReset", "(Ljava/lang/String;)V", (void *)reset}, - {"jniCheck", "(Ljava/lang/String;)I", (void *)check}, - {"jniAddAddress", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)addAddress}, - {"jniDelAddress", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)delAddress}, -}; - -int register_android_server_connectivity_Vpn(JNIEnv *env) -{ - if (inet4 == -1) { - inet4 = socket(AF_INET, SOCK_DGRAM, 0); - } - if (inet6 == -1) { - inet6 = socket(AF_INET6, SOCK_DGRAM, 0); - } - return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn", - gMethods, NELEM(gMethods)); -} - -}; diff --git a/service/jni/onload.cpp b/service/jni/onload.cpp index 3afcb0e8f6..00128794bc 100644 --- a/service/jni/onload.cpp +++ b/service/jni/onload.cpp @@ -19,7 +19,6 @@ namespace android { -int register_android_server_connectivity_Vpn(JNIEnv* env); int register_android_server_TestNetworkService(JNIEnv* env); extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { @@ -29,12 +28,11 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { return JNI_ERR; } - if (register_android_server_connectivity_Vpn(env) < 0 - || register_android_server_TestNetworkService(env) < 0) { + if (register_android_server_TestNetworkService(env) < 0) { return JNI_ERR; } return JNI_VERSION_1_6; } -}; \ No newline at end of file +};