下面列出了怎么用android.net.VpnService的API类实例代码及写法,或者点击链接到github查看源代码。
private void prepareStartService() {
if (app.isNatEnabled()) {
serviceLoad();
} else {
Intent intent = VpnService.prepare(mServiceBoundContext);
if (intent != null) {
startActivityForResult(intent, REQUEST_CONNECT);
} else {
handler.post(new Runnable() {
@Override
public void run() {
onActivityResult(REQUEST_CONNECT, RESULT_OK, null);
}
});
}
}
}
private void startBackgroundService() {
if (app.isNatEnabled()) {
try {
mServiceBoundContext.bgService.use(app.profileId());
finish();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Intent intent = VpnService.prepare(ShadowsocksRunnerActivity.this);
if (intent != null) {
startActivityForResult(intent, REQUEST_CONNECT);
} else {
onActivityResult(REQUEST_CONNECT, Activity.RESULT_OK, null);
}
}
}
/**
* 开始连接
*/
public void connectVpn() {
Intent intent = VpnService.prepare(this);
if (intent != null) {
VpnStatus.updateStateString("USER_VPN_PERMISSION", "", R.string.state_user_vpn_permission,
LEVEL_WAITING_FOR_USER_INPUT);
// Start the query
try {
startActivityForResult(intent, START_VPN_PROFILE);
} catch (ActivityNotFoundException ane) {
// Shame on you Sony! At least one user reported that
// an official Sony Xperia Arc S image triggers this exception
VpnStatus.logError(R.string.no_vpn_support_image);
}
} else {
onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null);
}
}
private void prepareStartService() {
if (ShadowsocksApplication.app.isNatEnabled()) {
serviceLoad();
} else {
Intent intent = VpnService.prepare(mServiceBoundContext);
if (intent != null) {
startActivityForResult(intent, REQUEST_CONNECT);
} else {
handler.post(new Runnable() {
@Override
public void run() {
onActivityResult(REQUEST_CONNECT, RESULT_OK, null);
}
});
}
}
}
private void startBackgroundService() {
if (ShadowsocksApplication.app.isNatEnabled()) {
try {
mServiceBoundContext.bgService.use(ShadowsocksApplication.app.profileId());
finish();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Intent intent = VpnService.prepare(ShadowsocksRunnerActivity.this);
if (intent != null) {
startActivityForResult(intent, REQUEST_CONNECT);
} else {
onActivityResult(REQUEST_CONNECT, Activity.RESULT_OK, null);
}
}
}
private void startVPNService() {
//Start VPN service if it is not started by modules presenters
final Intent prepareIntent = VpnService.prepare(modulesService);
if (handler != null && prepareIntent == null) {
handler.postDelayed(() -> {
if (modulesService != null && modulesStatus != null && sharedPreferences != null
&& !sharedPreferences.getBoolean("VPNServiceEnabled", false)
&& (modulesStatus.getDnsCryptState() == RUNNING || modulesStatus.getTorState() == RUNNING)) {
sharedPreferences.edit().putBoolean("VPNServiceEnabled", true).apply();
ServiceVPNHelper.start("ModulesStateLoop start VPN service", modulesService);
}
}, 10000);
}
}
private void stopServicesForeground(Context context, OperationMode mode, boolean fixTTL) {
if (mode == VPN_MODE || mode == ROOT_MODE && fixTTL) {
Intent stopVPNServiceForeground = new Intent(context, VpnService.class);
stopVPNServiceForeground.setAction(actionStopServiceForeground);
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
context.startService(stopVPNServiceForeground);
} else {
context.startForegroundService(stopVPNServiceForeground);
}
}
Intent stopModulesServiceForeground = new Intent(context, ModulesService.class);
stopModulesServiceForeground.setAction(actionStopServiceForeground);
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
context.startService(stopModulesServiceForeground);
} else {
context.startForegroundService(stopModulesServiceForeground);
}
Log.i(LOG_TAG, "BootCompleteReceiver stop running services foreground");
}
TcpProxyServer(VpnService vpnService, String ip, int mtu)
throws IOException {
super("TcpProxyServer");
this.mVpnService = vpnService;
this.mSelector = Selector.open();
this.mServerSocketChannel = ServerSocketChannel.open();
this.mServerSocketChannel.configureBlocking(false);
this.mServerSocketChannel.socket().bind(new InetSocketAddress(0));
this.mServerSocketChannel.register(mSelector, SelectionKey.OP_ACCEPT);
this.mIp = NetBareUtils.convertIp(ip);
this.mPort = (short) mServerSocketChannel.socket().getLocalPort();
this.mMtu = mtu;
NetBareLog.v("[TCP]proxy server: %s:%d", ip, NetBareUtils.convertPort(mPort));
}
private PacketsTransfer(VpnService service, NetBareConfig config) throws IOException {
int mtu = config.mtu;
String localIp = config.address.address;
UidDumper uidDumper = config.dumpUid ? new UidDumper(localIp, config.uidProvider) : null;
// Register all supported protocols here.
this.mForwarderRegistry = new LinkedHashMap<>(3);
// TCP
this.mForwarderRegistry.put(Protocol.TCP, new TcpProxyServerForwarder(service, localIp, mtu,
uidDumper));
// UDP
this.mForwarderRegistry.put(Protocol.UDP, new UdpProxyServerForwarder(service, mtu,
uidDumper));
// ICMP
this.mForwarderRegistry.put(Protocol.ICMP, new IcmpProxyServerForwarder());
buffer = new byte[mtu];
}
@Override
public void onReceive(final Context context, Intent intent) {
if (!Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
return;
}
LogWrapper.log(Log.DEBUG, LOG_TAG, "Boot event");
final VpnController controller = VpnController.getInstance();
VpnState state = controller.getState(context);
if (state.activationRequested && !state.on) {
LogWrapper.log(Log.DEBUG, LOG_TAG, "Autostart enabled");
if (VpnService.prepare(context) != null) {
// prepare() returns a non-null intent if VPN permission has not been granted.
LogWrapper.log(Log.WARN, LOG_TAG, "VPN permission not granted. Starting UI.");
Intent startIntent = new Intent(context, MainActivity.class);
startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startIntent);
return;
}
// Delay start until after the remote configuration has been updated, or failed to update.
RemoteConfig.update().addOnCompleteListener(success -> controller.start(context));
}
}
@Override
public void onClick() {
VpnState vpnState = VpnController.getInstance().getState(this);
if (vpnState.activationRequested) {
VpnController.getInstance().stop(this);
} else {
if (VpnService.prepare(this) == null) {
// Start VPN service when VPN permission has been granted.
VpnController.getInstance().start(this);
} else {
// Open Main activity when VPN permission has not been granted.
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityAndCollapse(intent);
}
}
}
public VpnService.Builder newBuilder() {
VpnService.Builder builder = new VpnService.Builder();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Some WebRTC apps rely on the ability to bind to specific interfaces, which is only
// possible if we allow bypass.
builder = builder.allowBypass();
try {
// Workaround for any app incompatibility bugs.
for (String packageName : PersistentState.getExcludedPackages(this)) {
builder = builder.addDisallowedApplication(packageName);
}
// Play Store incompatibility is a known issue, so always exclude it.
builder = builder.addDisallowedApplication("com.android.vending");
} catch (PackageManager.NameNotFoundException e) {
LogWrapper.logException(e);
Log.e(LOG_TAG, "Failed to exclude an app", e);
}
}
return builder;
}
private boolean prepareVpnService() throws ActivityNotFoundException {
Intent prepareVpnIntent = null;
try {
prepareVpnIntent = VpnService.prepare(this);
} catch (NullPointerException e) {
// This exception is not mentioned in the documentation, but it has been encountered by Intra
// users and also by other developers, e.g. https://stackoverflow.com/questions/45470113.
LogWrapper.logException(e);
return false;
}
if (prepareVpnIntent != null) {
Log.i(LOG_TAG, "Prepare VPN with activity");
startActivityForResult(prepareVpnIntent, REQUEST_CODE_PREPARE_VPN);
syncDnsStatus(); // Set DNS status to off in case the user does not grant VPN permissions
return false;
}
return true;
}
private static ParcelFileDescriptor establishVpn(IntraVpnService vpnService) {
try {
VpnService.Builder builder = vpnService.newBuilder()
.setSession("Intra go-tun2socks VPN")
.setMtu(VPN_INTERFACE_MTU)
.addAddress(LanIp.GATEWAY.make(IPV4_TEMPLATE), IPV4_PREFIX_LENGTH)
.addRoute("0.0.0.0", 0)
.addDnsServer(LanIp.DNS.make(IPV4_TEMPLATE));
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
builder.addDisallowedApplication(vpnService.getPackageName());
}
return builder.establish();
} catch (Exception e) {
LogWrapper.logException(e);
return null;
}
}
/**
* Apply allow or disallow rule on application by package names.
*/
private void applyApplicationOrientedRule(VpnService.Builder builder) {
boolean workInAllowMode = PreferenceUtils.getBooleanPreference(getContentResolver(),
Uri.parse(Constants.PREFERENCE_URI),
Constants.PREFERENCE_KEY_PROXY_IN_ALLOW_MODE, false);
Set<String> exemptAppPackageNames = getExemptAppPackageNames(workInAllowMode);
RuleApplier applier;
if (workInAllowMode) {
exemptAppPackageNames.remove(getPackageName()); // disallow Igniter
applier = Builder::addAllowedApplication;
} else {
exemptAppPackageNames.add(getPackageName()); // disallow Igniter
applier = Builder::addDisallowedApplication;
}
for (String packageName : exemptAppPackageNames) {
try {
applier.applyRule(builder, packageName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
setState(STOPPED);
}
}
}
private void startVpn() {
stopwatch = new Stopwatch();
connectedServer = currentServer;
hideCurrentConnection = true;
adbBlockCheck.setEnabled(false);
Intent intent = VpnService.prepare(this);
if (intent != null) {
VpnStatus.updateStateString("USER_VPN_PERMISSION", "", R.string.state_user_vpn_permission,
VpnStatus.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT);
// Start the query
try {
startActivityForResult(intent, START_VPN_PROFILE);
} catch (ActivityNotFoundException ane) {
// Shame on you Sony! At least one user reported that
// an official Sony Xperia Arc S image triggers this exception
VpnStatus.logError(R.string.no_vpn_support_image);
}
} else {
onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null);
}
}
private void startProfile(VpnProfile vp) {
Intent vpnPermissionIntent = VpnService.prepare(ExternalOpenVPNService.this);
/* Check if we need to show the confirmation dialog,
* Check if we need to ask for username/password */
int needpw = vp.needUserPWInput(false);
if (vpnPermissionIntent != null || needpw != 0) {
Intent shortVPNIntent = new Intent(Intent.ACTION_MAIN);
shortVPNIntent.setClass(getBaseContext(), ht.vpn.android.LaunchVPN.class);
shortVPNIntent.putExtra(ht.vpn.android.LaunchVPN.EXTRA_KEY, vp.getUUIDString());
shortVPNIntent.putExtra(ht.vpn.android.LaunchVPN.EXTRA_HIDELOG, true);
shortVPNIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(shortVPNIntent);
} else {
VPNLaunchHelper.startOpenVpn(vp, getBaseContext());
}
}
/**
* Checks if a VPN app supports always-on mode.
*
* In order to support the always-on feature, an app has to
* <ul>
* <li>target {@link VERSION_CODES#N API 24} or above, and
* <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
* meta-data field.
* </ul>
*
* @param packageName the canonical package name of the VPN app
* @return {@code true} if and only if the VPN app exists and supports always-on mode
*/
public boolean isAlwaysOnPackageSupported(String packageName) {
enforceSettingsPermission();
if (packageName == null) {
return false;
}
PackageManager pm = mContext.getPackageManager();
ApplicationInfo appInfo = null;
try {
appInfo = pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserHandle);
} catch (NameNotFoundException unused) {
Log.w(TAG, "Can't find \"" + packageName + "\" when checking always-on support");
}
if (appInfo == null || appInfo.targetSdkVersion < VERSION_CODES.N) {
return false;
}
final Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
intent.setPackage(packageName);
List<ResolveInfo> services =
pm.queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, mUserHandle);
if (services == null || services.size() == 0) {
return false;
}
for (ResolveInfo rInfo : services) {
final Bundle metaData = rInfo.serviceInfo.metaData;
if (metaData != null &&
!metaData.getBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, true)) {
return false;
}
}
return true;
}
/**
* Prepare for vpn connect with required permission
*/
private void prepareVpn() {
if (!vpnStart) {
if (getInternetStatus()) {
// Checking permission for network monitor
Intent intent = VpnService.prepare(getContext());
if (intent != null) {
startActivityForResult(intent, 1);
} else startVpn();//have already permission
// Update confection status
status("connecting");
} else {
// No internet connection available
showToast("you have no internet connection !!");
}
} else if (stopVpn()) {
// VPN is stopped, show a Toast message.
showToast("Disconnect Successfully");
}
}
@Override
protected void onServiceConnected() {
if (bgService != null) {
if (app.isNatEnabled()) {
startBackgroundService();
} else if (VpnService.prepare(ShadowsocksRunnerService.this) == null) {
startBackgroundService();
} else {
handler.postDelayed(mStopSelfRunnable, 10000);
}
}
}
@Override
public IBinder onBind(Intent intent) {
String action = intent.getAction();
if (VpnService.SERVICE_INTERFACE.equals(action)) {
return super.onBind(intent);
} else if (Constants.Action.SERVICE.equals(action)) {
return binder;
}
return super.onBind(intent);
}
@Override
public void startRunner(Profile profile) {
// ensure the VPNService is prepared
if (VpnService.prepare(this) != null) {
Intent i = new Intent(this, ShadowsocksRunnerActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
stopRunner(true);
return;
}
super.startRunner(profile);
}
@Override
protected void onServiceConnected() {
if (bgService != null) {
if (ShadowsocksApplication.app.isNatEnabled()) {
startBackgroundService();
} else if (VpnService.prepare(ShadowsocksRunnerService.this) == null) {
startBackgroundService();
} else {
handler.postDelayed(mStopSelfRunnable, 10000);
}
}
}
@NonNull
@Override
public VpnService.Builder setMtu(int mtu) {
this.mtu = mtu;
super.setMtu(mtu);
return this;
}
@NonNull
@Override
public VpnService.Builder addAllowedApplication(@NonNull String packageName) throws PackageManager.NameNotFoundException {
listAllowed.add(packageName);
performAllowedOrDisallowed = "allowed";
super.addAllowedApplication(packageName);
return this;
}
public void prepareVPNService() {
Log.i(LOG_TAG, "MainActivity prepare VPN Service");
final Intent prepareIntent = VpnService.prepare(this);
if (prepareIntent == null) {
startVPNService(RESULT_OK);
} else if (!vpnRequested){
vpnRequested = true;
startActivityForResult(prepareIntent, CODE_IS_VPN_ALLOWED);
}
}
UdpProxyServer(VpnService vpnService, int mtu) throws IOException {
super("UdpProxyServer");
this.mVpnService = vpnService;
this.mMtu = mtu;
this.mSelector = Selector.open();
this.mTunnels = new ConcurrentHashMap<>();
}
private void startVPN()
{
Intent vpnIntent = VpnService.prepare(this);
if (vpnIntent != null)
{
startActivityForResult(vpnIntent, VPN_REQUEST_CODE);
}
else
{
onActivityResult(VPN_REQUEST_CODE, RESULT_OK, null);
}
}
private void startDNS() {
if (presenter.isWorking()) {
presenter.stopService();
} else if (isValid()) {
Intent intent = VpnService.prepare(this);
if (intent != null) {
startActivityForResult(intent, REQUEST_CONNECT);
} else {
onActivityResult(REQUEST_CONNECT, RESULT_OK, null);
}
} else {
makeSnackbar(getString(R.string.enter_valid_dns));
}
}
@SuppressWarnings("unused")
public static RelayTunnel open(VpnService vpnService) throws IOException {
Log.d(TAG, "Opening a new relay tunnel...");
// since we use a local socket, we don't need to protect the socket from the vpnService anymore
// but this is an implementation detail, so keep the method signature
return new RelayTunnel();
}