1ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/* 2ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Copyright (C) 2011 The Android Open Source Project 3ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 4ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Licensed under the Apache License, Version 2.0 (the "License"); 5ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * you may not use this file except in compliance with the License. 6ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * You may obtain a copy of the License at 7ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 8ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * http://www.apache.org/licenses/LICENSE-2.0 9ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 10ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Unless required by applicable law or agreed to in writing, software 11ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * distributed under the License is distributed on an "AS IS" BASIS, 12ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * See the License for the specific language governing permissions and 14ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * limitations under the License. 15ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 16ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 17ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehpackage com.android.server.connectivity; 18ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 19ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.app.Notification; 20ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.app.NotificationManager; 21199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.ComponentName; 22ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Context; 23ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Intent; 24199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.ServiceConnection; 25ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.pm.ApplicationInfo; 26ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.pm.PackageManager; 27199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.content.pm.ResolveInfo; 28ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.res.Resources; 29ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.graphics.Bitmap; 30ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.graphics.Canvas; 31ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.graphics.drawable.Drawable; 32ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.net.INetworkManagementEventObserver; 3385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocket; 3485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocketAddress; 35ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.Binder; 36199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.os.IBinder; 37199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yehimport android.os.Parcel; 38ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.ParcelFileDescriptor; 3985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.Process; 4085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.SystemClock; 4185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.SystemProperties; 42ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.util.Log; 43ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 44ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport com.android.internal.R; 452e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yehimport com.android.internal.net.LegacyVpnInfo; 4604ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yehimport com.android.internal.net.VpnConfig; 47ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport com.android.server.ConnectivityService.VpnCallback; 48ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 4997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehimport java.io.File; 5097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehimport java.io.FileInputStream; 5197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yehimport java.io.InputStream; 5285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport java.io.OutputStream; 5385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport java.nio.charset.Charsets; 5441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yehimport java.util.Arrays; 5585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 56ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/** 57ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @hide 58ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 59ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehpublic class Vpn extends INetworkManagementEventObserver.Stub { 60ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 61ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final static String TAG = "Vpn"; 62ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 63199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private final static String BIND_VPN_SERVICE = 64199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh android.Manifest.permission.BIND_VPN_SERVICE; 65199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 66ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final Context mContext; 67ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final VpnCallback mCallback; 68ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 69c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private String mPackage = VpnConfig.LEGACY_VPN; 70c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private String mInterface; 71199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private Connection mConnection; 7285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private LegacyVpnRunner mLegacyVpnRunner; 73ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 74ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh public Vpn(Context context, VpnCallback callback) { 75ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext = context; 76ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mCallback = callback; 77ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 78ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 79ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh /** 80100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * Prepare for a VPN application. This method is designed to solve 81100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * race conditions. It first compares the current prepared package 82100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * with {@code oldPackage}. If they are the same, the prepared 83100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * package is revoked and replaced with {@code newPackage}. If 84100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * {@code oldPackage} is {@code null}, the comparison is omitted. 85100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * If {@code newPackage} is the same package or {@code null}, the 86100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * revocation is omitted. This method returns {@code true} if the 87100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * operation is succeeded. 88e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * 89100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * Legacy VPN is handled specially since it is not a real package. 90100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and 91100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * it can be revoked by itself. 92100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * 93100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @param oldPackage The package name of the old VPN application. 94100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @param newPackage The package name of the new VPN application. 95100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * @return true if the operation is succeeded. 96ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 97100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh public synchronized boolean prepare(String oldPackage, String newPackage) { 98100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Return false if the package does not match. 99c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (oldPackage != null && !oldPackage.equals(mPackage)) { 100100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh return false; 101100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh } 102100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh 103100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Return true if we do not need to revoke. 104100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh if (newPackage == null || 105c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh (newPackage.equals(mPackage) && !newPackage.equals(VpnConfig.LEGACY_VPN))) { 106100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh return true; 107ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 108ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 109100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Only system user can revoke a package. 11041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (Binder.getCallingUid() != Process.SYSTEM_UID) { 11141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh throw new SecurityException("Unauthorized Caller"); 11241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 1137b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh 114ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Reset the interface and hide the notification. 115c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (mInterface != null) { 116c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh jniReset(mInterface); 1177b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh mCallback.restore(); 118ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh hideNotification(); 119c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = null; 120ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 121ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 122fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh // Revoke the connection or stop LegacyVpnRunner. 123199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh if (mConnection != null) { 124199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh try { 125199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION, 126199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Parcel.obtain(), null, IBinder.FLAG_ONEWAY); 127199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } catch (Exception e) { 128199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh // ignore 129199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 130199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mContext.unbindService(mConnection); 131199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mConnection = null; 132e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh } else if (mLegacyVpnRunner != null) { 13341d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mLegacyVpnRunner.exit(); 13441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mLegacyVpnRunner = null; 13541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 13641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 137c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh Log.i(TAG, "Switched from " + mPackage + " to " + newPackage); 138c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mPackage = newPackage; 139100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh return true; 140ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 141ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 142ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh /** 143fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh * Protect a socket from routing changes by binding it to the given 144fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh * interface. The socket is NOT closed by this method. 145fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh * 146fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh * @param socket The socket to be bound. 147fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh * @param name The name of the interface. 148fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh */ 149fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception { 150fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh PackageManager pm = mContext.getPackageManager(); 151fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh ApplicationInfo app = pm.getApplicationInfo(mPackage, 0); 152fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh if (Binder.getCallingUid() != app.uid) { 153fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh throw new SecurityException("Unauthorized Caller"); 154fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh } 155fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh jniProtect(socket.getFd(), interfaze); 156fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh } 157fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh 158fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh /** 159e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * Establish a VPN network and return the file descriptor of the VPN 160e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * interface. This methods returns {@code null} if the application is 161100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh * revoked or not prepared. 162ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 163e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @param config The parameters to configure the network. 164e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @return The file descriptor of the VPN interface. 165ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 16604ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yeh public synchronized ParcelFileDescriptor establish(VpnConfig config) { 167ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Check if the caller is already prepared. 168ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh PackageManager pm = mContext.getPackageManager(); 169ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh ApplicationInfo app = null; 170ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 171c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh app = pm.getApplicationInfo(mPackage, 0); 172ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (Exception e) { 1737b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh return null; 174ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 175ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (Binder.getCallingUid() != app.uid) { 1767b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh return null; 177ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 178ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 179fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh // Check if the service is properly declared. 180199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE); 181199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh intent.setClassName(mPackage, config.user); 182199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh ResolveInfo info = pm.resolveService(intent, 0); 183199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh if (info == null) { 184199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh throw new SecurityException("Cannot find " + config.user); 185199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 186199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) { 187199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE); 188199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 189fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh 190a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh // Load the label. 191a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh String label = app.loadLabel(pm).toString(); 192a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh 193a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh // Load the icon and convert it into a bitmap. 194a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh Drawable icon = app.loadIcon(pm); 195a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh Bitmap bitmap = null; 196a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) { 197a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh int width = mContext.getResources().getDimensionPixelSize( 198a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh android.R.dimen.notification_large_icon_width); 199a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh int height = mContext.getResources().getDimensionPixelSize( 200a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh android.R.dimen.notification_large_icon_height); 201a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh icon.setBounds(0, 0, width, height); 202a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 2036311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn Canvas c = new Canvas(bitmap); 2046311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn icon.draw(c); 2056311d0a079702b29984c0d31937345be105e1a5eDianne Hackborn c.setBitmap(null); 206a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh } 207a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh 208e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Configure the interface. Abort if any of these steps fails. 20997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); 210ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 211c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh String interfaze = jniGetName(tun.getFd()); 21297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (jniSetAddresses(interfaze, config.addresses) < 1) { 21397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalArgumentException("At least one address must be specified"); 21497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 21597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (config.routes != null) { 21697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh jniSetRoutes(interfaze, config.routes); 21797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 218199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Connection connection = new Connection(); 219199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh if (!mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE)) { 220199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh throw new IllegalStateException("Cannot bind " + config.user); 221199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 222199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh if (mConnection != null) { 223199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mContext.unbindService(mConnection); 224199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 225c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (mInterface != null && !mInterface.equals(interfaze)) { 226c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh jniReset(mInterface); 227ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 228199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mConnection = connection; 229c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = interfaze; 230ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (RuntimeException e) { 231ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 232c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh tun.close(); 233ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (Exception ex) { 234ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // ignore 235ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 236ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh throw e; 237ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 238199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh Log.i(TAG, "Established by " + config.user + " on " + mInterface); 239ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 2408909b10175303bd5e2ca82b7ba12cd0017050ef3Chia-chi Yeh // Fill more values. 241fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh config.user = mPackage; 242c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh config.interfaze = mInterface; 2438909b10175303bd5e2ca82b7ba12cd0017050ef3Chia-chi Yeh 244fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh // Override DNS servers and show the notification. 245fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh long identity = Binder.clearCallingIdentity(); 246fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh mCallback.override(config.dnsServers, config.searchDomains); 247383e0524726d64302322abeba16d87faf66bae99Chia-chi Yeh showNotification(config, label, bitmap); 248fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh Binder.restoreCallingIdentity(identity); 249c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh return tun; 250ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 251ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 252ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // INetworkManagementEventObserver.Stub 253fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh @Override 254aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh public void interfaceAdded(String interfaze) { 255f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen } 256f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen 257f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen // INetworkManagementEventObserver.Stub 258fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh @Override 259aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh public synchronized void interfaceStatusChanged(String interfaze, boolean up) { 260aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh if (!up && mLegacyVpnRunner != null) { 261aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh mLegacyVpnRunner.check(interfaze); 262aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 263ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 264ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 265ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // INetworkManagementEventObserver.Stub 266fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh @Override 267fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh public void interfaceLinkStateChanged(String interfaze, boolean up) { 268ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 269ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 270ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // INetworkManagementEventObserver.Stub 271fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh @Override 272c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh public synchronized void interfaceRemoved(String interfaze) { 273c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { 274fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh long identity = Binder.clearCallingIdentity(); 275ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mCallback.restore(); 276e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh hideNotification(); 277fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh Binder.restoreCallingIdentity(identity); 278c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = null; 279199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh if (mConnection != null) { 280199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mContext.unbindService(mConnection); 281199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mConnection = null; 2820c074e68437f1a705a8e73ac32e8e4dec370ec43Chia-chi Yeh } else if (mLegacyVpnRunner != null) { 2830c074e68437f1a705a8e73ac32e8e4dec370ec43Chia-chi Yeh mLegacyVpnRunner.exit(); 2840c074e68437f1a705a8e73ac32e8e4dec370ec43Chia-chi Yeh mLegacyVpnRunner = null; 285199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 286ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 287ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 288ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 289fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh // INetworkManagementEventObserver.Stub 290fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh @Override 291fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh public void limitReached(String limit, String interfaze) { 292fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh } 29312b933d0d9252decaae9fee2456bb1e1cd94c085JP Abgrall 294199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private class Connection implements ServiceConnection { 295199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh private IBinder mService; 296199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 297199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh @Override 298199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh public void onServiceConnected(ComponentName name, IBinder service) { 299199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mService = service; 300199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 301199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 302199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh @Override 303199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh public void onServiceDisconnected(ComponentName name) { 304199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh mService = null; 305199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 306199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh } 307199ed6ef89bd356895534ba09ac43ed340cd9a1aChia-chi Yeh 308a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh private void showNotification(VpnConfig config, String label, Bitmap icon) { 309ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh NotificationManager nm = (NotificationManager) 310ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext.getSystemService(Context.NOTIFICATION_SERVICE); 311ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 312ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (nm != null) { 313a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh String title = (label == null) ? mContext.getString(R.string.vpn_title) : 314a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh mContext.getString(R.string.vpn_title_long, label); 31534e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh String text = (config.session == null) ? mContext.getString(R.string.vpn_text) : 31634e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh mContext.getString(R.string.vpn_text_long, config.session); 3172e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh config.startTime = SystemClock.elapsedRealtime(); 318a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh 319ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh Notification notification = new Notification.Builder(mContext) 320ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .setSmallIcon(R.drawable.vpn_connected) 321a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh .setLargeIcon(icon) 322a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh .setContentTitle(title) 323f8905fd13da0bfd6049daebc1cf4f8af286a04deChia-chi Yeh .setContentText(text) 3242e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh .setContentIntent(VpnConfig.getIntentForStatusPanel(mContext, config)) 32550fe709995d1f126e96cafde133bc4777b31d4edChia-chi Yeh .setDefaults(0) 326ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .setOngoing(true) 327ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .getNotification(); 328ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh nm.notify(R.drawable.vpn_connected, notification); 329ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 330ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 331ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 332ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private void hideNotification() { 333ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh NotificationManager nm = (NotificationManager) 334ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext.getSystemService(Context.NOTIFICATION_SERVICE); 335ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 336ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (nm != null) { 337ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh nm.cancel(R.drawable.vpn_connected); 338ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 339ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 340ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 34197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh private native int jniCreate(int mtu); 342c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native String jniGetName(int tun); 34397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh private native int jniSetAddresses(String interfaze, String addresses); 34497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh private native int jniSetRoutes(String interfaze, String routes); 345c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native void jniReset(String interfaze); 346c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native int jniCheck(String interfaze); 347c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh private native void jniProtect(int socket, String interfaze); 34885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 34985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 3502e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh * Start legacy VPN. This method stops the daemons and restart them 3512e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh * if arguments are not null. Heavy things are offloaded to another 352e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * thread, so callers will not be blocked for a long time. 35385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * 354e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh * @param config The parameters to configure the network. 35585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * @param raoocn The arguments to be passed to racoon. 35685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * @param mtpd The arguments to be passed to mtpd. 35785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 3582e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { 359100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh // Prepare for the new request. This also checks the caller. 360100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh prepare(null, VpnConfig.LEGACY_VPN); 36185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 3622e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Start a new LegacyVpnRunner and we are done! 363100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); 364100155a310fbb5028fc48e359bdfb7c4d3531843Chia-chi Yeh mLegacyVpnRunner.start(); 36585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 36685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 36785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 3682e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh * Return the information of the current ongoing legacy VPN. 3692e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh */ 3702e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh public synchronized LegacyVpnInfo getLegacyVpnInfo() { 3712e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Only system user can call this method. 3722e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh if (Binder.getCallingUid() != Process.SYSTEM_UID) { 3732e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh throw new SecurityException("Unauthorized Caller"); 3742e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 3752e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo(); 3762e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 3772e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 3782e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh /** 37985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * Bringing up a VPN connection takes time, and that is all this thread 38085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * does. Here we have plenty of time. The only thing we need to take 38185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * care of is responding to interruptions as soon as possible. Otherwise 38285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * requests will be piled up. This can be done in a Handler as a state 38385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * machine, but it is much easier to read in the current form. 38485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 38585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private class LegacyVpnRunner extends Thread { 38685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private static final String TAG = "LegacyVpnRunner"; 38785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 38841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh private final VpnConfig mConfig; 3891f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh private final String[] mDaemons; 39085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private final String[][] mArguments; 3915317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh private final LocalSocket[] mSockets; 392aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh private final String mOuterInterface; 3932e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh private final LegacyVpnInfo mInfo; 3942e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 39585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private long mTimer = -1; 39685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 39741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) { 39885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh super(TAG); 39941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mConfig = config; 40041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mDaemons = new String[] {"racoon", "mtpd"}; 40141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mArguments = new String[][] {racoon, mtpd}; 4025317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets = new LocalSocket[mDaemons.length]; 4032e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo = new LegacyVpnInfo(); 404e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh 405aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh // This is the interface which VPN is running on. 406aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh mOuterInterface = mConfig.interfaze; 407aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh 4082e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Legacy VPN is not a real package, so we use it to carry the key. 409fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh mInfo.key = mConfig.user; 410fcc1b41b663c1a0cb551344c4a16a5ad9ce36d60Chia-chi Yeh mConfig.user = VpnConfig.LEGACY_VPN; 41141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 41241d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 413aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh public void check(String interfaze) { 414aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh if (interfaze.equals(mOuterInterface)) { 415aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh Log.i(TAG, "Legacy VPN is going down with " + interfaze); 416aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh exit(); 417aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 418aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh } 419aa1727fe0cbb902c5f53a3fae601b4e15da0a2f4Chia-chi Yeh 42041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh public void exit() { 4215317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh // We assume that everything is reset after stopping the daemons. 42297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh interrupt(); 4235317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh for (LocalSocket socket : mSockets) { 4245317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh try { 4255317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh socket.close(); 4265317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh } catch (Exception e) { 4275317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh // ignore 4285317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh } 42941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 43085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 43185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 4322e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh public LegacyVpnInfo getInfo() { 4332e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Update the info when VPN is disconnected. 4342e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh if (mInfo.state == LegacyVpnInfo.STATE_CONNECTED && mInterface == null) { 4352e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED; 4362e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.intent = null; 4372e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 4382e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh return mInfo; 4392e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 4402e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 44185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh @Override 44285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh public void run() { 44385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the previous thread since it has been interrupted. 4442e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.v(TAG, "Waiting"); 44585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh synchronized (TAG) { 4462e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.v(TAG, "Executing"); 44785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh execute(); 44885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 44985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 45085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 45185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void checkpoint(boolean yield) throws InterruptedException { 45285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh long now = SystemClock.elapsedRealtime(); 45385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (mTimer == -1) { 45485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mTimer = now; 45585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(1); 4567ef8611b5f3a893a46c7b9e22bdd8ab252e373ffChia-chi Yeh } else if (now - mTimer <= 60000) { 45785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(yield ? 200 : 1); 45885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } else { 4592e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_TIMEOUT; 46097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Time is up"); 46185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 46285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 46385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 46485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void execute() { 46585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Catch all exceptions so we can clean up few things. 46685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 46785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Initialize the timer. 46885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 4692e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_INITIALIZING; 47085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 4711f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Wait for the daemons to stop. 4721f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (String daemon : mDaemons) { 4731f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String key = "init.svc." + daemon; 4745317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh while (!"stopped".equals(SystemProperties.get(key, "stopped"))) { 47585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 47685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 47785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 47885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 47997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Clear the previous state. 48097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh File state = new File("/data/misc/vpn/state"); 48197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh state.delete(); 48297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (state.exists()) { 48397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Cannot delete the state"); 48485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 485c1872732922214de80f790e14865e41dd1b98203Chia-chi Yeh new File("/data/misc/vpn/abort").delete(); 48685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 487e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Check if we need to restart any of the daemons. 48885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh boolean restart = false; 48985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String[] arguments : mArguments) { 49085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh restart = restart || (arguments != null); 49185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 49285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (!restart) { 4932e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED; 49485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh return; 49585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 4962e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_CONNECTING; 49785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 4981f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Start the daemon with arguments. 4991f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (int i = 0; i < mDaemons.length; ++i) { 50085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh String[] arguments = mArguments[i]; 50185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (arguments == null) { 50285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh continue; 50385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 50485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 5051f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Start the daemon. 5061f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String daemon = mDaemons[i]; 5071f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh SystemProperties.set("ctl.start", daemon); 50885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 5091f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Wait for the daemon to start. 5101f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String key = "init.svc." + daemon; 51185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (!"running".equals(SystemProperties.get(key))) { 51285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 51385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 51485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 51585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Create the control socket. 5165317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i] = new LocalSocket(); 51785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh LocalSocketAddress address = new LocalSocketAddress( 5181f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh daemon, LocalSocketAddress.Namespace.RESERVED); 51985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 52085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the socket to connect. 52185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (true) { 52285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 5235317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i].connect(address); 52485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh break; 52585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 52685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // ignore 52785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 52885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 52985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 5305317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh mSockets[i].setSoTimeout(500); 53185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 53285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Send over the arguments. 5335317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh OutputStream out = mSockets[i].getOutputStream(); 53485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String argument : arguments) { 53585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh byte[] bytes = argument.getBytes(Charsets.UTF_8); 5365317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh if (bytes.length >= 0xFFFF) { 53797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalArgumentException("Argument is too large"); 53885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 5391f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes.length >> 8); 5401f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes.length); 5411f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.write(bytes); 54285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 54385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 5445317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh out.write(0xFF); 5455317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh out.write(0xFF); 5461f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh out.flush(); 54797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 54897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Wait for End-of-File. 5495317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh InputStream in = mSockets[i].getInputStream(); 55097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh while (true) { 55197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh try { 55297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (in.read() == -1) { 55397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh break; 55497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 55597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } catch (Exception e) { 55697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // ignore 55797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 55897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh checkpoint(true); 55997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 56085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 56185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 56297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Wait for the daemons to create the new state. 56397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh while (!state.exists()) { 5641f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh // Check if a running daemon is dead. 5651f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh for (int i = 0; i < mDaemons.length; ++i) { 5661f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh String daemon = mDaemons[i]; 56785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (mArguments[i] != null && !"running".equals( 5681f7746b39b94be1149228751e45a40ea39603611Chia-chi Yeh SystemProperties.get("init.svc." + daemon))) { 5692e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh throw new IllegalStateException(daemon + " is dead"); 57085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 57185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 57285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 57385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 57485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 57597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Now we are connected. Read and parse the new state. 57697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh byte[] buffer = new byte[(int) state.length()]; 57797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (new FileInputStream(state).read(buffer) != buffer.length) { 57897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Cannot read the state"); 57997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 58097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh String[] parameters = new String(buffer, Charsets.UTF_8).split("\n", -1); 58197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (parameters.length != 6) { 58297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh throw new IllegalStateException("Cannot parse the state"); 58397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 58497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 58597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the interface and the addresses in the config. 58697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh mConfig.interfaze = parameters[0].trim(); 58797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh mConfig.addresses = parameters[1].trim(); 58885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 58997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the routes if they are not set in the config. 59097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (mConfig.routes == null || mConfig.routes.isEmpty()) { 59197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh mConfig.routes = parameters[2].trim(); 59297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 59397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 59497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the DNS servers if they are not set in the config. 59541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) { 59697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh String dnsServers = parameters[3].trim(); 59741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh if (!dnsServers.isEmpty()) { 59841d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mConfig.dnsServers = Arrays.asList(dnsServers.split(" ")); 59941d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 60041d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 60141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 60297a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the search domains if they are not set in the config. 60397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) { 60497a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh String searchDomains = parameters[4].trim(); 60597a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh if (!searchDomains.isEmpty()) { 60697a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh mConfig.searchDomains = Arrays.asList(searchDomains.split(" ")); 60797a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 60897a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh } 60997a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh 61097a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Set the routes. 61197a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh jniSetRoutes(mConfig.interfaze, mConfig.routes); 612e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh 61397a61565ea95472e65899070e64853f8c147bb11Chia-chi Yeh // Here is the last step and it must be done synchronously. 61441d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh synchronized (Vpn.this) { 61541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh // Check if the thread is interrupted while we are waiting. 61641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh checkpoint(false); 61741d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh 618e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Check if the interface is gone while we are waiting. 619c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh if (jniCheck(mConfig.interfaze) == 0) { 62034e7813e962de99df9813014678ef5901227c5f1Chia-chi Yeh throw new IllegalStateException(mConfig.interfaze + " is gone"); 62141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 622e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh 623e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh // Now INetworkManagementEventObserver is watching our back. 624c2b8aa0b4c822b0e307f62131650f4a6ee89bb66Chia-chi Yeh mInterface = mConfig.interfaze; 62541d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh mCallback.override(mConfig.dnsServers, mConfig.searchDomains); 62641d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh showNotification(mConfig, null, null); 6272e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh 6282e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.i(TAG, "Connected!"); 6292e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_CONNECTED; 6302e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.intent = VpnConfig.getIntentForStatusPanel(mContext, null); 63141d1685a22ba8038517d6fdb57006023e03f12e1Chia-chi Yeh } 63285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 6332e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh Log.i(TAG, "Aborting", e); 634e9107901ae264de4ff5603d3cfc63a03ca4117d4Chia-chi Yeh exit(); 6352e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } finally { 6365317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh // Kill the daemons if they fail to stop. 6375317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING) { 6385317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh for (String daemon : mDaemons) { 6395317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh SystemProperties.set("ctl.stop", daemon); 6405317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh } 6415317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh } 6425317f034bacaab19af3181da8e9752cbb5b09a08Chia-chi Yeh 6432e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh // Do not leave an unstable state. 6442e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING || 6452e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state == LegacyVpnInfo.STATE_CONNECTING) { 6462e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh mInfo.state = LegacyVpnInfo.STATE_FAILED; 6472e46764a707bd14cad22bc179669eeecb2d7c647Chia-chi Yeh } 64885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 64985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 65085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 651ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh} 652