Merge "Begin moving VPN to NetworkStateTracker pattern." into jb-mr1-dev
This commit is contained in:
153
core/java/android/net/BaseNetworkStateTracker.java
Normal file
153
core/java/android/net/BaseNetworkStateTracker.java
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import com.android.internal.util.Preconditions;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to control and observe state of a specific network, hiding
|
||||||
|
* network-specific details from {@link ConnectivityManager}. Surfaces events
|
||||||
|
* through the registered {@link Handler} to enable {@link ConnectivityManager}
|
||||||
|
* to respond to state changes over time.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public abstract class BaseNetworkStateTracker implements NetworkStateTracker {
|
||||||
|
// TODO: better document threading expectations
|
||||||
|
// TODO: migrate to make NetworkStateTracker abstract class
|
||||||
|
|
||||||
|
public static final String PROP_TCP_BUFFER_UNKNOWN = "net.tcp.buffersize.unknown";
|
||||||
|
public static final String PROP_TCP_BUFFER_WIFI = "net.tcp.buffersize.wifi";
|
||||||
|
|
||||||
|
protected Context mContext;
|
||||||
|
private Handler mTarget;
|
||||||
|
|
||||||
|
protected NetworkInfo mNetworkInfo;
|
||||||
|
protected LinkProperties mLinkProperties;
|
||||||
|
protected LinkCapabilities mLinkCapabilities;
|
||||||
|
|
||||||
|
private AtomicBoolean mTeardownRequested = new AtomicBoolean(false);
|
||||||
|
private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false);
|
||||||
|
private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
public BaseNetworkStateTracker(int networkType) {
|
||||||
|
mNetworkInfo = new NetworkInfo(
|
||||||
|
networkType, -1, ConnectivityManager.getNetworkTypeName(networkType), null);
|
||||||
|
mLinkProperties = new LinkProperties();
|
||||||
|
mLinkCapabilities = new LinkCapabilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
protected Handler getTargetHandler() {
|
||||||
|
return mTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void dispatchStateChanged() {
|
||||||
|
// TODO: include snapshot of other fields when sending
|
||||||
|
mTarget.obtainMessage(EVENT_STATE_CHANGED, getNetworkInfo()).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void dispatchConfigurationChanged() {
|
||||||
|
// TODO: include snapshot of other fields when sending
|
||||||
|
mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, getNetworkInfo()).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void startMonitoring(Context context, Handler target) {
|
||||||
|
mContext = Preconditions.checkNotNull(context);
|
||||||
|
mTarget = Preconditions.checkNotNull(target);
|
||||||
|
startMonitoringInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void startMonitoringInternal();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final NetworkInfo getNetworkInfo() {
|
||||||
|
return new NetworkInfo(mNetworkInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final LinkProperties getLinkProperties() {
|
||||||
|
return new LinkProperties(mLinkProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final LinkCapabilities getLinkCapabilities() {
|
||||||
|
return new LinkCapabilities(mLinkCapabilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setRadio(boolean turnOn) {
|
||||||
|
// Base tracker doesn't handle radios
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
return mNetworkInfo.isAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUserDataEnable(boolean enabled) {
|
||||||
|
// Base tracker doesn't handle enabled flags
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPolicyDataEnable(boolean enabled) {
|
||||||
|
// Base tracker doesn't handle enabled flags
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPrivateDnsRouteSet() {
|
||||||
|
return mPrivateDnsRouteSet.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void privateDnsRouteSet(boolean enabled) {
|
||||||
|
mPrivateDnsRouteSet.set(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDefaultRouteSet() {
|
||||||
|
return mDefaultRouteSet.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void defaultRouteSet(boolean enabled) {
|
||||||
|
mDefaultRouteSet.set(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTeardownRequested() {
|
||||||
|
return mTeardownRequested.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTeardownRequested(boolean isRequested) {
|
||||||
|
mTeardownRequested.set(isRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDependencyMet(boolean met) {
|
||||||
|
// Base tracker doesn't handle dependencies
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package android.os;
|
package android.os;
|
||||||
|
|
||||||
|
import android.util.Slog;
|
||||||
|
|
||||||
import com.google.android.collect.Maps;
|
import com.google.android.collect.Maps;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -81,7 +83,7 @@ public class SystemService {
|
|||||||
if (state != null) {
|
if (state != null) {
|
||||||
return state;
|
return state;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Service " + service + " in unknown state " + rawState);
|
return State.STOPPED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,10 @@
|
|||||||
package com.android.internal.net;
|
package com.android.internal.net;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple container used to carry information of the ongoing legacy VPN.
|
* A simple container used to carry information of the ongoing legacy VPN.
|
||||||
@@ -27,6 +29,8 @@ import android.os.Parcelable;
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public class LegacyVpnInfo implements Parcelable {
|
public class LegacyVpnInfo implements Parcelable {
|
||||||
|
private static final String TAG = "LegacyVpnInfo";
|
||||||
|
|
||||||
public static final int STATE_DISCONNECTED = 0;
|
public static final int STATE_DISCONNECTED = 0;
|
||||||
public static final int STATE_INITIALIZING = 1;
|
public static final int STATE_INITIALIZING = 1;
|
||||||
public static final int STATE_CONNECTING = 2;
|
public static final int STATE_CONNECTING = 2;
|
||||||
@@ -66,4 +70,25 @@ public class LegacyVpnInfo implements Parcelable {
|
|||||||
return new LegacyVpnInfo[size];
|
return new LegacyVpnInfo[size];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return best matching {@link LegacyVpnInfo} state based on given
|
||||||
|
* {@link NetworkInfo}.
|
||||||
|
*/
|
||||||
|
public static int stateFromNetworkInfo(NetworkInfo info) {
|
||||||
|
switch (info.getDetailedState()) {
|
||||||
|
case CONNECTING:
|
||||||
|
return STATE_CONNECTING;
|
||||||
|
case CONNECTED:
|
||||||
|
return STATE_CONNECTED;
|
||||||
|
case DISCONNECTED:
|
||||||
|
return STATE_DISCONNECTED;
|
||||||
|
case FAILED:
|
||||||
|
return STATE_FAILED;
|
||||||
|
default:
|
||||||
|
Log.w(TAG, "Unhandled state " + info.getDetailedState()
|
||||||
|
+ " ; treating as disconnected");
|
||||||
|
return STATE_DISCONNECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import android.content.Intent;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.android.internal.util.Preconditions;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,13 +47,14 @@ public class VpnConfig implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static PendingIntent getIntentForStatusPanel(Context context, VpnConfig config) {
|
public static PendingIntent getIntentForStatusPanel(Context context, VpnConfig config) {
|
||||||
|
Preconditions.checkNotNull(config);
|
||||||
|
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog");
|
intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog");
|
||||||
intent.putExtra("config", config);
|
intent.putExtra("config", config);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
|
||||||
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
|
||||||
return PendingIntent.getActivity(context, 0, intent, (config == null) ?
|
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||||
PendingIntent.FLAG_NO_CREATE : PendingIntent.FLAG_CANCEL_CURRENT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String user;
|
public String user;
|
||||||
@@ -64,6 +67,7 @@ public class VpnConfig implements Parcelable {
|
|||||||
public List<String> searchDomains;
|
public List<String> searchDomains;
|
||||||
public PendingIntent configureIntent;
|
public PendingIntent configureIntent;
|
||||||
public long startTime = -1;
|
public long startTime = -1;
|
||||||
|
public boolean legacy;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
@@ -82,6 +86,7 @@ public class VpnConfig implements Parcelable {
|
|||||||
out.writeStringList(searchDomains);
|
out.writeStringList(searchDomains);
|
||||||
out.writeParcelable(configureIntent, flags);
|
out.writeParcelable(configureIntent, flags);
|
||||||
out.writeLong(startTime);
|
out.writeLong(startTime);
|
||||||
|
out.writeInt(legacy ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<VpnConfig> CREATOR =
|
public static final Parcelable.Creator<VpnConfig> CREATOR =
|
||||||
@@ -99,6 +104,7 @@ public class VpnConfig implements Parcelable {
|
|||||||
config.searchDomains = in.createStringArrayList();
|
config.searchDomains = in.createStringArrayList();
|
||||||
config.configureIntent = in.readParcelable(null);
|
config.configureIntent = in.readParcelable(null);
|
||||||
config.startTime = in.readLong();
|
config.startTime = in.readLong();
|
||||||
|
config.legacy = in.readInt() != 0;
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ public class ManageDialog extends AlertActivity implements
|
|||||||
mDataReceived = (TextView) view.findViewById(R.id.data_received);
|
mDataReceived = (TextView) view.findViewById(R.id.data_received);
|
||||||
mDataRowsHidden = true;
|
mDataRowsHidden = true;
|
||||||
|
|
||||||
if (mConfig.user.equals(VpnConfig.LEGACY_VPN)) {
|
if (mConfig.legacy) {
|
||||||
mAlertParams.mIconId = android.R.drawable.ic_dialog_info;
|
mAlertParams.mIconId = android.R.drawable.ic_dialog_info;
|
||||||
mAlertParams.mTitle = getText(R.string.legacy_title);
|
mAlertParams.mTitle = getText(R.string.legacy_title);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -115,13 +115,15 @@ import java.util.List;
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public class ConnectivityService extends IConnectivityManager.Stub {
|
public class ConnectivityService extends IConnectivityManager.Stub {
|
||||||
|
private static final String TAG = "ConnectivityService";
|
||||||
|
|
||||||
private static final boolean DBG = true;
|
private static final boolean DBG = true;
|
||||||
private static final boolean VDBG = false;
|
private static final boolean VDBG = false;
|
||||||
private static final String TAG = "ConnectivityService";
|
|
||||||
|
|
||||||
private static final boolean LOGD_RULES = false;
|
private static final boolean LOGD_RULES = false;
|
||||||
|
|
||||||
|
// TODO: create better separation between radio types and network types
|
||||||
|
|
||||||
// how long to wait before switching back to a radio's default network
|
// how long to wait before switching back to a radio's default network
|
||||||
private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
|
private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000;
|
||||||
// system property that can override the above value
|
// system property that can override the above value
|
||||||
@@ -136,6 +138,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
private boolean mTetheringConfigValid = false;
|
private boolean mTetheringConfigValid = false;
|
||||||
|
|
||||||
private Vpn mVpn;
|
private Vpn mVpn;
|
||||||
|
private VpnCallback mVpnCallback = new VpnCallback();
|
||||||
|
|
||||||
/** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
|
/** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
|
||||||
private Object mRulesLock = new Object();
|
private Object mRulesLock = new Object();
|
||||||
@@ -328,7 +331,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
this(context, netd, statsService, policyManager, null);
|
this(context, netd, statsService, policyManager, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConnectivityService(Context context, INetworkManagementService netd,
|
public ConnectivityService(Context context, INetworkManagementService netManager,
|
||||||
INetworkStatsService statsService, INetworkPolicyManager policyManager,
|
INetworkStatsService statsService, INetworkPolicyManager policyManager,
|
||||||
NetworkFactory netFactory) {
|
NetworkFactory netFactory) {
|
||||||
if (DBG) log("ConnectivityService starting up");
|
if (DBG) log("ConnectivityService starting up");
|
||||||
@@ -366,7 +369,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mContext = checkNotNull(context, "missing Context");
|
mContext = checkNotNull(context, "missing Context");
|
||||||
mNetd = checkNotNull(netd, "missing INetworkManagementService");
|
mNetd = checkNotNull(netManager, "missing INetworkManagementService");
|
||||||
mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
|
mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -506,11 +509,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
mTethering.getTetherableBluetoothRegexs().length != 0) &&
|
mTethering.getTetherableBluetoothRegexs().length != 0) &&
|
||||||
mTethering.getUpstreamIfaceTypes().length != 0);
|
mTethering.getUpstreamIfaceTypes().length != 0);
|
||||||
|
|
||||||
mVpn = new Vpn(mContext, new VpnCallback());
|
mVpn = new Vpn(mContext, mVpnCallback, mNetd);
|
||||||
|
mVpn.startMonitoring(mContext, mTrackerHandler);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mNetd.registerObserver(mTethering);
|
mNetd.registerObserver(mTethering);
|
||||||
mNetd.registerObserver(mVpn);
|
|
||||||
mNetd.registerObserver(mDataActivityObserver);
|
mNetd.registerObserver(mDataActivityObserver);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
loge("Error registering observer :" + e);
|
loge("Error registering observer :" + e);
|
||||||
@@ -2238,9 +2241,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
*/
|
*/
|
||||||
public void updateNetworkSettings(NetworkStateTracker nt) {
|
public void updateNetworkSettings(NetworkStateTracker nt) {
|
||||||
String key = nt.getTcpBufferSizesPropName();
|
String key = nt.getTcpBufferSizesPropName();
|
||||||
String bufferSizes = SystemProperties.get(key);
|
String bufferSizes = key == null ? null : SystemProperties.get(key);
|
||||||
|
|
||||||
if (bufferSizes.length() == 0) {
|
if (TextUtils.isEmpty(bufferSizes)) {
|
||||||
if (VDBG) log(key + " not found in system properties. Using defaults");
|
if (VDBG) log(key + " not found in system properties. Using defaults");
|
||||||
|
|
||||||
// Setting to default values so we won't be stuck to previous values
|
// Setting to default values so we won't be stuck to previous values
|
||||||
@@ -3153,10 +3156,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
|||||||
* be done whenever a better abstraction is developed.
|
* be done whenever a better abstraction is developed.
|
||||||
*/
|
*/
|
||||||
public class VpnCallback {
|
public class VpnCallback {
|
||||||
|
|
||||||
private VpnCallback() {
|
private VpnCallback() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onStateChanged(NetworkInfo info) {
|
||||||
|
// TODO: if connected, release delayed broadcast
|
||||||
|
// TODO: if disconnected, consider kicking off reconnect
|
||||||
|
}
|
||||||
|
|
||||||
public void override(List<String> dnsServers, List<String> searchDomains) {
|
public void override(List<String> dnsServers, List<String> searchDomains) {
|
||||||
if (dnsServers == null) {
|
if (dnsServers == null) {
|
||||||
restore();
|
restore();
|
||||||
|
|||||||
@@ -16,8 +16,11 @@
|
|||||||
|
|
||||||
package com.android.server.connectivity;
|
package com.android.server.connectivity;
|
||||||
|
|
||||||
|
import static android.Manifest.permission.BIND_VPN_SERVICE;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -28,15 +31,21 @@ import android.content.pm.ResolveInfo;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.BaseNetworkStateTracker;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
import android.net.INetworkManagementEventObserver;
|
import android.net.INetworkManagementEventObserver;
|
||||||
import android.net.LocalSocket;
|
import android.net.LocalSocket;
|
||||||
import android.net.LocalSocketAddress;
|
import android.net.LocalSocketAddress;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.NetworkInfo.DetailedState;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.FileUtils;
|
import android.os.FileUtils;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.INetworkManagementService;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.SystemService;
|
import android.os.SystemService;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -44,7 +53,9 @@ import android.util.Log;
|
|||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
import com.android.internal.net.LegacyVpnInfo;
|
import com.android.internal.net.LegacyVpnInfo;
|
||||||
import com.android.internal.net.VpnConfig;
|
import com.android.internal.net.VpnConfig;
|
||||||
|
import com.android.internal.util.Preconditions;
|
||||||
import com.android.server.ConnectivityService.VpnCallback;
|
import com.android.server.ConnectivityService.VpnCallback;
|
||||||
|
import com.android.server.net.BaseNetworkObserver;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -57,24 +68,63 @@ import libcore.io.IoUtils;
|
|||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public class Vpn extends INetworkManagementEventObserver.Stub {
|
public class Vpn extends BaseNetworkStateTracker {
|
||||||
|
private static final String TAG = "Vpn";
|
||||||
|
private static final boolean LOGD = true;
|
||||||
|
|
||||||
private final static String TAG = "Vpn";
|
// TODO: create separate trackers for each unique VPN to support
|
||||||
|
// automated reconnection
|
||||||
|
|
||||||
private final static String BIND_VPN_SERVICE =
|
|
||||||
android.Manifest.permission.BIND_VPN_SERVICE;
|
|
||||||
|
|
||||||
private final Context mContext;
|
|
||||||
private final VpnCallback mCallback;
|
private final VpnCallback mCallback;
|
||||||
|
|
||||||
private String mPackage = VpnConfig.LEGACY_VPN;
|
private String mPackage = VpnConfig.LEGACY_VPN;
|
||||||
private String mInterface;
|
private String mInterface;
|
||||||
private Connection mConnection;
|
private Connection mConnection;
|
||||||
private LegacyVpnRunner mLegacyVpnRunner;
|
private LegacyVpnRunner mLegacyVpnRunner;
|
||||||
|
private PendingIntent mStatusIntent;
|
||||||
|
|
||||||
public Vpn(Context context, VpnCallback callback) {
|
public Vpn(Context context, VpnCallback callback, INetworkManagementService netService) {
|
||||||
|
// TODO: create dedicated TYPE_VPN network type
|
||||||
|
super(ConnectivityManager.TYPE_DUMMY);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mCallback = callback;
|
mCallback = callback;
|
||||||
|
|
||||||
|
try {
|
||||||
|
netService.registerObserver(mObserver);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.wtf(TAG, "Problem registering observer", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void startMonitoringInternal() {
|
||||||
|
// Ignored; events are sent through callbacks for now
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean teardown() {
|
||||||
|
// TODO: finish migration to unique tracker for each VPN
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean reconnect() {
|
||||||
|
// TODO: finish migration to unique tracker for each VPN
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTcpBufferSizesPropName() {
|
||||||
|
return PROP_TCP_BUFFER_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update current state, dispaching event to listeners.
|
||||||
|
*/
|
||||||
|
private void updateState(DetailedState detailedState, String reason) {
|
||||||
|
if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
|
||||||
|
mNetworkInfo.setDetailedState(detailedState, reason, null);
|
||||||
|
mCallback.onStateChanged(new NetworkInfo(mNetworkInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,10 +163,13 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
// Reset the interface and hide the notification.
|
// Reset the interface and hide the notification.
|
||||||
if (mInterface != null) {
|
if (mInterface != null) {
|
||||||
jniReset(mInterface);
|
jniReset(mInterface);
|
||||||
long identity = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
mCallback.restore();
|
try {
|
||||||
hideNotification();
|
mCallback.restore();
|
||||||
Binder.restoreCallingIdentity(identity);
|
hideNotification();
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(token);
|
||||||
|
}
|
||||||
mInterface = null;
|
mInterface = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +190,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
|
|
||||||
Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
|
Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
|
||||||
mPackage = newPackage;
|
mPackage = newPackage;
|
||||||
|
updateState(DetailedState.IDLE, "prepare");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +199,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
* interface. The socket is NOT closed by this method.
|
* interface. The socket is NOT closed by this method.
|
||||||
*
|
*
|
||||||
* @param socket The socket to be bound.
|
* @param socket The socket to be bound.
|
||||||
* @param name The name of the interface.
|
* @param interfaze The name of the interface.
|
||||||
*/
|
*/
|
||||||
public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
|
public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
|
||||||
PackageManager pm = mContext.getPackageManager();
|
PackageManager pm = mContext.getPackageManager();
|
||||||
@@ -209,6 +263,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
// Configure the interface. Abort if any of these steps fails.
|
// Configure the interface. Abort if any of these steps fails.
|
||||||
ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
|
ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
|
||||||
try {
|
try {
|
||||||
|
updateState(DetailedState.CONNECTING, "establish");
|
||||||
String interfaze = jniGetName(tun.getFd());
|
String interfaze = jniGetName(tun.getFd());
|
||||||
if (jniSetAddresses(interfaze, config.addresses) < 1) {
|
if (jniSetAddresses(interfaze, config.addresses) < 1) {
|
||||||
throw new IllegalArgumentException("At least one address must be specified");
|
throw new IllegalArgumentException("At least one address must be specified");
|
||||||
@@ -229,6 +284,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
mConnection = connection;
|
mConnection = connection;
|
||||||
mInterface = interfaze;
|
mInterface = interfaze;
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
|
updateState(DetailedState.FAILED, "establish");
|
||||||
IoUtils.closeQuietly(tun);
|
IoUtils.closeQuietly(tun);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@@ -239,57 +295,61 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
config.interfaze = mInterface;
|
config.interfaze = mInterface;
|
||||||
|
|
||||||
// Override DNS servers and show the notification.
|
// Override DNS servers and show the notification.
|
||||||
long identity = Binder.clearCallingIdentity();
|
final long token = Binder.clearCallingIdentity();
|
||||||
mCallback.override(config.dnsServers, config.searchDomains);
|
try {
|
||||||
showNotification(config, label, bitmap);
|
mCallback.override(config.dnsServers, config.searchDomains);
|
||||||
Binder.restoreCallingIdentity(identity);
|
showNotification(config, label, bitmap);
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(token);
|
||||||
|
}
|
||||||
|
// TODO: ensure that contract class eventually marks as connected
|
||||||
|
updateState(DetailedState.AUTHENTICATING, "establish");
|
||||||
return tun;
|
return tun;
|
||||||
}
|
}
|
||||||
|
|
||||||
// INetworkManagementEventObserver.Stub
|
@Deprecated
|
||||||
@Override
|
public synchronized void interfaceStatusChanged(String iface, boolean up) {
|
||||||
public void interfaceAdded(String interfaze) {
|
try {
|
||||||
}
|
mObserver.interfaceStatusChanged(iface, up);
|
||||||
|
} catch (RemoteException e) {
|
||||||
// INetworkManagementEventObserver.Stub
|
// ignored; target is local
|
||||||
@Override
|
|
||||||
public synchronized void interfaceStatusChanged(String interfaze, boolean up) {
|
|
||||||
if (!up && mLegacyVpnRunner != null) {
|
|
||||||
mLegacyVpnRunner.check(interfaze);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// INetworkManagementEventObserver.Stub
|
private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() {
|
||||||
@Override
|
@Override
|
||||||
public void interfaceLinkStateChanged(String interfaze, boolean up) {
|
public void interfaceStatusChanged(String interfaze, boolean up) {
|
||||||
}
|
synchronized (Vpn.this) {
|
||||||
|
if (!up && mLegacyVpnRunner != null) {
|
||||||
// INetworkManagementEventObserver.Stub
|
mLegacyVpnRunner.check(interfaze);
|
||||||
@Override
|
}
|
||||||
public synchronized void interfaceRemoved(String interfaze) {
|
|
||||||
if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
|
|
||||||
long identity = Binder.clearCallingIdentity();
|
|
||||||
mCallback.restore();
|
|
||||||
hideNotification();
|
|
||||||
Binder.restoreCallingIdentity(identity);
|
|
||||||
mInterface = null;
|
|
||||||
if (mConnection != null) {
|
|
||||||
mContext.unbindService(mConnection);
|
|
||||||
mConnection = null;
|
|
||||||
} else if (mLegacyVpnRunner != null) {
|
|
||||||
mLegacyVpnRunner.exit();
|
|
||||||
mLegacyVpnRunner = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// INetworkManagementEventObserver.Stub
|
@Override
|
||||||
@Override
|
public void interfaceRemoved(String interfaze) {
|
||||||
public void limitReached(String limit, String interfaze) {
|
synchronized (Vpn.this) {
|
||||||
}
|
if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
|
||||||
|
final long token = Binder.clearCallingIdentity();
|
||||||
public void interfaceClassDataActivityChanged(String label, boolean active) {
|
try {
|
||||||
}
|
mCallback.restore();
|
||||||
|
hideNotification();
|
||||||
|
} finally {
|
||||||
|
Binder.restoreCallingIdentity(token);
|
||||||
|
}
|
||||||
|
mInterface = null;
|
||||||
|
if (mConnection != null) {
|
||||||
|
mContext.unbindService(mConnection);
|
||||||
|
mConnection = null;
|
||||||
|
updateState(DetailedState.DISCONNECTED, "interfaceRemoved");
|
||||||
|
} else if (mLegacyVpnRunner != null) {
|
||||||
|
mLegacyVpnRunner.exit();
|
||||||
|
mLegacyVpnRunner = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private void enforceControlPermission() {
|
private void enforceControlPermission() {
|
||||||
// System user is allowed to control VPN.
|
// System user is allowed to control VPN.
|
||||||
@@ -326,6 +386,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showNotification(VpnConfig config, String label, Bitmap icon) {
|
private void showNotification(VpnConfig config, String label, Bitmap icon) {
|
||||||
|
mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext, config);
|
||||||
|
|
||||||
NotificationManager nm = (NotificationManager)
|
NotificationManager nm = (NotificationManager)
|
||||||
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
@@ -341,15 +403,17 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
.setLargeIcon(icon)
|
.setLargeIcon(icon)
|
||||||
.setContentTitle(title)
|
.setContentTitle(title)
|
||||||
.setContentText(text)
|
.setContentText(text)
|
||||||
.setContentIntent(VpnConfig.getIntentForStatusPanel(mContext, config))
|
.setContentIntent(mStatusIntent)
|
||||||
.setDefaults(0)
|
.setDefaults(0)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.getNotification();
|
.build();
|
||||||
nm.notify(R.drawable.vpn_connected, notification);
|
nm.notify(R.drawable.vpn_connected, notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void hideNotification() {
|
private void hideNotification() {
|
||||||
|
mStatusIntent = null;
|
||||||
|
|
||||||
NotificationManager nm = (NotificationManager)
|
NotificationManager nm = (NotificationManager)
|
||||||
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
|
||||||
@@ -372,25 +436,51 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
* thread, so callers will not be blocked for a long time.
|
* thread, so callers will not be blocked for a long time.
|
||||||
*
|
*
|
||||||
* @param config The parameters to configure the network.
|
* @param config The parameters to configure the network.
|
||||||
* @param raoocn The arguments to be passed to racoon.
|
* @param racoon The arguments to be passed to racoon.
|
||||||
* @param mtpd The arguments to be passed to mtpd.
|
* @param mtpd The arguments to be passed to mtpd.
|
||||||
*/
|
*/
|
||||||
public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
|
public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
|
||||||
|
stopLegacyVpn();
|
||||||
|
|
||||||
|
// TODO: move legacy definition to settings
|
||||||
|
config.legacy = true;
|
||||||
|
|
||||||
// Prepare for the new request. This also checks the caller.
|
// Prepare for the new request. This also checks the caller.
|
||||||
prepare(null, VpnConfig.LEGACY_VPN);
|
prepare(null, VpnConfig.LEGACY_VPN);
|
||||||
|
updateState(DetailedState.CONNECTING, "startLegacyVpn");
|
||||||
|
|
||||||
// Start a new LegacyVpnRunner and we are done!
|
// Start a new LegacyVpnRunner and we are done!
|
||||||
mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
|
mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
|
||||||
mLegacyVpnRunner.start();
|
mLegacyVpnRunner.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void stopLegacyVpn() {
|
||||||
|
if (mLegacyVpnRunner != null) {
|
||||||
|
mLegacyVpnRunner.exit();
|
||||||
|
mLegacyVpnRunner = null;
|
||||||
|
|
||||||
|
synchronized (LegacyVpnRunner.TAG) {
|
||||||
|
// wait for old thread to completely finish before spinning up
|
||||||
|
// new instance, otherwise state updates can be out of order.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the information of the current ongoing legacy VPN.
|
* Return the information of the current ongoing legacy VPN.
|
||||||
*/
|
*/
|
||||||
public synchronized LegacyVpnInfo getLegacyVpnInfo() {
|
public synchronized LegacyVpnInfo getLegacyVpnInfo() {
|
||||||
// Check if the caller is authorized.
|
// Check if the caller is authorized.
|
||||||
enforceControlPermission();
|
enforceControlPermission();
|
||||||
return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo();
|
if (mLegacyVpnRunner == null) return null;
|
||||||
|
|
||||||
|
final LegacyVpnInfo info = new LegacyVpnInfo();
|
||||||
|
info.key = mLegacyVpnRunner.mConfig.user;
|
||||||
|
info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
|
||||||
|
if (mNetworkInfo.isConnected()) {
|
||||||
|
info.intent = mStatusIntent;
|
||||||
|
}
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -407,8 +497,6 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
private final String[] mDaemons;
|
private final String[] mDaemons;
|
||||||
private final String[][] mArguments;
|
private final String[][] mArguments;
|
||||||
private final LocalSocket[] mSockets;
|
private final LocalSocket[] mSockets;
|
||||||
private final String mOuterInterface;
|
|
||||||
private final LegacyVpnInfo mInfo;
|
|
||||||
|
|
||||||
private long mTimer = -1;
|
private long mTimer = -1;
|
||||||
|
|
||||||
@@ -416,20 +504,13 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
super(TAG);
|
super(TAG);
|
||||||
mConfig = config;
|
mConfig = config;
|
||||||
mDaemons = new String[] {"racoon", "mtpd"};
|
mDaemons = new String[] {"racoon", "mtpd"};
|
||||||
|
// TODO: clear arguments from memory once launched
|
||||||
mArguments = new String[][] {racoon, mtpd};
|
mArguments = new String[][] {racoon, mtpd};
|
||||||
mSockets = new LocalSocket[mDaemons.length];
|
mSockets = new LocalSocket[mDaemons.length];
|
||||||
mInfo = new LegacyVpnInfo();
|
|
||||||
|
|
||||||
// This is the interface which VPN is running on.
|
|
||||||
mOuterInterface = mConfig.interfaze;
|
|
||||||
|
|
||||||
// Legacy VPN is not a real package, so we use it to carry the key.
|
|
||||||
mInfo.key = mConfig.user;
|
|
||||||
mConfig.user = VpnConfig.LEGACY_VPN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void check(String interfaze) {
|
public void check(String interfaze) {
|
||||||
if (interfaze.equals(mOuterInterface)) {
|
if (interfaze.equals(mConfig.interfaze)) {
|
||||||
Log.i(TAG, "Legacy VPN is going down with " + interfaze);
|
Log.i(TAG, "Legacy VPN is going down with " + interfaze);
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
@@ -441,15 +522,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
for (LocalSocket socket : mSockets) {
|
for (LocalSocket socket : mSockets) {
|
||||||
IoUtils.closeQuietly(socket);
|
IoUtils.closeQuietly(socket);
|
||||||
}
|
}
|
||||||
}
|
updateState(DetailedState.DISCONNECTED, "exit");
|
||||||
|
|
||||||
public LegacyVpnInfo getInfo() {
|
|
||||||
// Update the info when VPN is disconnected.
|
|
||||||
if (mInfo.state == LegacyVpnInfo.STATE_CONNECTED && mInterface == null) {
|
|
||||||
mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED;
|
|
||||||
mInfo.intent = null;
|
|
||||||
}
|
|
||||||
return mInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -459,6 +532,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
synchronized (TAG) {
|
synchronized (TAG) {
|
||||||
Log.v(TAG, "Executing");
|
Log.v(TAG, "Executing");
|
||||||
execute();
|
execute();
|
||||||
|
monitorDaemons();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,17 +544,17 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
} else if (now - mTimer <= 60000) {
|
} else if (now - mTimer <= 60000) {
|
||||||
Thread.sleep(yield ? 200 : 1);
|
Thread.sleep(yield ? 200 : 1);
|
||||||
} else {
|
} else {
|
||||||
mInfo.state = LegacyVpnInfo.STATE_TIMEOUT;
|
updateState(DetailedState.FAILED, "checkpoint");
|
||||||
throw new IllegalStateException("Time is up");
|
throw new IllegalStateException("Time is up");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void execute() {
|
private void execute() {
|
||||||
// Catch all exceptions so we can clean up few things.
|
// Catch all exceptions so we can clean up few things.
|
||||||
|
boolean initFinished = false;
|
||||||
try {
|
try {
|
||||||
// Initialize the timer.
|
// Initialize the timer.
|
||||||
checkpoint(false);
|
checkpoint(false);
|
||||||
mInfo.state = LegacyVpnInfo.STATE_INITIALIZING;
|
|
||||||
|
|
||||||
// Wait for the daemons to stop.
|
// Wait for the daemons to stop.
|
||||||
for (String daemon : mDaemons) {
|
for (String daemon : mDaemons) {
|
||||||
@@ -496,6 +570,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
throw new IllegalStateException("Cannot delete the state");
|
throw new IllegalStateException("Cannot delete the state");
|
||||||
}
|
}
|
||||||
new File("/data/misc/vpn/abort").delete();
|
new File("/data/misc/vpn/abort").delete();
|
||||||
|
initFinished = true;
|
||||||
|
|
||||||
// Check if we need to restart any of the daemons.
|
// Check if we need to restart any of the daemons.
|
||||||
boolean restart = false;
|
boolean restart = false;
|
||||||
@@ -503,10 +578,10 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
restart = restart || (arguments != null);
|
restart = restart || (arguments != null);
|
||||||
}
|
}
|
||||||
if (!restart) {
|
if (!restart) {
|
||||||
mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED;
|
updateState(DetailedState.DISCONNECTED, "execute");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mInfo.state = LegacyVpnInfo.STATE_CONNECTING;
|
updateState(DetailedState.CONNECTING, "execute");
|
||||||
|
|
||||||
// Start the daemon with arguments.
|
// Start the daemon with arguments.
|
||||||
for (int i = 0; i < mDaemons.length; ++i) {
|
for (int i = 0; i < mDaemons.length; ++i) {
|
||||||
@@ -633,26 +708,53 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
|
|||||||
showNotification(mConfig, null, null);
|
showNotification(mConfig, null, null);
|
||||||
|
|
||||||
Log.i(TAG, "Connected!");
|
Log.i(TAG, "Connected!");
|
||||||
mInfo.state = LegacyVpnInfo.STATE_CONNECTED;
|
updateState(DetailedState.CONNECTED, "execute");
|
||||||
mInfo.intent = VpnConfig.getIntentForStatusPanel(mContext, null);
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.i(TAG, "Aborting", e);
|
Log.i(TAG, "Aborting", e);
|
||||||
exit();
|
exit();
|
||||||
} finally {
|
} finally {
|
||||||
// Kill the daemons if they fail to stop.
|
// Kill the daemons if they fail to stop.
|
||||||
if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING) {
|
if (!initFinished) {
|
||||||
for (String daemon : mDaemons) {
|
for (String daemon : mDaemons) {
|
||||||
SystemService.stop(daemon);
|
SystemService.stop(daemon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not leave an unstable state.
|
// Do not leave an unstable state.
|
||||||
if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING ||
|
if (!initFinished || mNetworkInfo.getDetailedState() == DetailedState.CONNECTING) {
|
||||||
mInfo.state == LegacyVpnInfo.STATE_CONNECTING) {
|
updateState(DetailedState.FAILED, "execute");
|
||||||
mInfo.state = LegacyVpnInfo.STATE_FAILED;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitor the daemons we started, moving to disconnected state if the
|
||||||
|
* underlying services fail.
|
||||||
|
*/
|
||||||
|
private void monitorDaemons() {
|
||||||
|
if (!mNetworkInfo.isConnected()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
for (int i = 0; i < mDaemons.length; i++) {
|
||||||
|
if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.d(TAG, "interrupted during monitorDaemons(); stopping services");
|
||||||
|
} finally {
|
||||||
|
for (String daemon : mDaemons) {
|
||||||
|
SystemService.stop(daemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateState(DetailedState.DISCONNECTED, "babysit");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user