Vpn.java revision a4b87b5e980ffa52e9bc5549688b588b1b99a1eb
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; 21ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Context; 22ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.Intent; 23ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.pm.ApplicationInfo; 24ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.pm.PackageManager; 25ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.content.res.Resources; 26ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.graphics.Bitmap; 27ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.graphics.Canvas; 28ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.graphics.drawable.Drawable; 29ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.net.INetworkManagementEventObserver; 3085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocket; 3185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.net.LocalSocketAddress; 32ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.Binder; 33ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.os.ParcelFileDescriptor; 3485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.Process; 3585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.SystemClock; 3685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport android.os.SystemProperties; 37ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport android.util.Log; 38ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 39ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport com.android.internal.R; 4004ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yehimport com.android.internal.net.VpnConfig; 41ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehimport com.android.server.ConnectivityService.VpnCallback; 42ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 4385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport java.io.OutputStream; 4485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yehimport java.nio.charset.Charsets; 4585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 46ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh/** 47ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @hide 48ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 49ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yehpublic class Vpn extends INetworkManagementEventObserver.Stub { 50ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 51ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final static String TAG = "Vpn"; 52ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final static String VPN = android.Manifest.permission.VPN; 53ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 54ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final Context mContext; 55ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private final VpnCallback mCallback; 56ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 57ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private String mPackageName; 58ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private String mInterfaceName; 5985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 6085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private LegacyVpnRunner mLegacyVpnRunner; 61ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 62ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh public Vpn(Context context, VpnCallback callback) { 63ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext = context; 64ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mCallback = callback; 65ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 66ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 67ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh /** 68ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Prepare for a VPN application. 69ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 70ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @param packageName The package name of the new VPN application. 71ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @return The name of the current prepared package. 72ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 73ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh public synchronized String prepare(String packageName) { 747b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh // Return the current prepared package if the new one is null. 75ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (packageName == null) { 76ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh return mPackageName; 77ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 78ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 797b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh // Check the permission of the caller. 80ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh PackageManager pm = mContext.getPackageManager(); 817b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh VpnConfig.enforceCallingPackage(pm.getNameForUid(Binder.getCallingUid())); 827b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh 837b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh // Check the permission of the given package. 847b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh if (packageName.isEmpty()) { 857b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh packageName = null; 867b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh } else if (pm.checkPermission(VPN, packageName) != PackageManager.PERMISSION_GRANTED) { 87ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh throw new SecurityException(packageName + " does not have " + VPN); 88ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 89ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 90ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Reset the interface and hide the notification. 91ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (mInterfaceName != null) { 92f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh jniResetInterface(mInterfaceName); 937b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh mCallback.restore(); 94ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh hideNotification(); 957b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh mInterfaceName = null; 96ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 97ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 987b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh // Notify the package being revoked. 997b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh if (mPackageName != null) { 1007b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh Intent intent = new Intent(VpnConfig.ACTION_VPN_REVOKED); 1017b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh intent.setPackage(mPackageName); 1027b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 1037b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh mContext.sendBroadcast(intent); 1047b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh } 1057b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh 1067b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh Log.i(TAG, "Switched from " + mPackageName + " to " + packageName); 107ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mPackageName = packageName; 108ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh return mPackageName; 109ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 110ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 111ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh /** 112ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Protect a socket from routing changes by binding it to the given 1133f3337a662e9916bbf14502ef3b32dedaa7adfa4Chia-chi Yeh * interface. The socket IS closed by this method. 114ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 115ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @param socket The socket to be bound. 116ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @param name The name of the interface. 117ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 118ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh public void protect(ParcelFileDescriptor socket, String name) { 1193f3337a662e9916bbf14502ef3b32dedaa7adfa4Chia-chi Yeh try { 1203f3337a662e9916bbf14502ef3b32dedaa7adfa4Chia-chi Yeh mContext.enforceCallingPermission(VPN, "protect"); 121f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh jniProtectSocket(socket.getFd(), name); 1223f3337a662e9916bbf14502ef3b32dedaa7adfa4Chia-chi Yeh } finally { 1233f3337a662e9916bbf14502ef3b32dedaa7adfa4Chia-chi Yeh try { 1243f3337a662e9916bbf14502ef3b32dedaa7adfa4Chia-chi Yeh socket.close(); 1253f3337a662e9916bbf14502ef3b32dedaa7adfa4Chia-chi Yeh } catch (Exception e) { 1263f3337a662e9916bbf14502ef3b32dedaa7adfa4Chia-chi Yeh // ignore 1273f3337a662e9916bbf14502ef3b32dedaa7adfa4Chia-chi Yeh } 1283f3337a662e9916bbf14502ef3b32dedaa7adfa4Chia-chi Yeh } 129ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 130ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 131ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh /** 132ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * Configure a TUN interface and return its file descriptor. 133ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * 134a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh * @param config The parameters to configure the interface. 135ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh * @return The file descriptor of the interface. 136ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh */ 13704ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yeh public synchronized ParcelFileDescriptor establish(VpnConfig config) { 138ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Check the permission of the caller. 139ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext.enforceCallingPermission(VPN, "establish"); 140ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 141ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // Check if the caller is already prepared. 142ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh PackageManager pm = mContext.getPackageManager(); 143ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh ApplicationInfo app = null; 144ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 145ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh app = pm.getApplicationInfo(mPackageName, 0); 146ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (Exception e) { 1477b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh return null; 148ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 149ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (Binder.getCallingUid() != app.uid) { 1507b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh return null; 151ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 152ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 153a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh // Load the label. 154a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh String label = app.loadLabel(pm).toString(); 155a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh 156a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh // Load the icon and convert it into a bitmap. 157a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh Drawable icon = app.loadIcon(pm); 158a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh Bitmap bitmap = null; 159a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) { 160a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh int width = mContext.getResources().getDimensionPixelSize( 161a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh android.R.dimen.notification_large_icon_width); 162a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh int height = mContext.getResources().getDimensionPixelSize( 163a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh android.R.dimen.notification_large_icon_height); 164a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh icon.setBounds(0, 0, width, height); 165a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 166a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh icon.draw(new Canvas(bitmap)); 167a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh } 168a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh 169a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh // Create the interface and abort if any of the following steps fails. 170f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh ParcelFileDescriptor descriptor = 171f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh ParcelFileDescriptor.adoptFd(jniCreateInterface(config.mtu)); 172ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 173f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh String name = jniGetInterfaceName(descriptor.getFd()); 174f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh if (jniSetAddresses(name, config.addresses) < 1) { 175f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh throw new IllegalArgumentException("At least one address must be specified"); 176f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh } 177f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh if (config.routes != null) { 178f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh jniSetRoutes(name, config.routes); 179f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh } 180f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh if (mInterfaceName != null && !mInterfaceName.equals(name)) { 181f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh jniResetInterface(mInterfaceName); 182ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 183f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh mInterfaceName = name; 184ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (RuntimeException e) { 185ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh try { 186ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh descriptor.close(); 187ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } catch (Exception ex) { 188ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // ignore 189ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 190ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh throw e; 191ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 192ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 19304ba25c418bc4538e9dc0f047cfb9608d358f679Chia-chi Yeh String dnsServers = (config.dnsServers == null) ? "" : config.dnsServers.trim(); 194ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mCallback.override(dnsServers.isEmpty() ? null : dnsServers.split(" ")); 195ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 1967b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh config.packageName = mPackageName; 1977b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh config.interfaceName = mInterfaceName; 1987b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh showNotification(pm, app, config); 199ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh return descriptor; 200ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 201ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 202ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // INetworkManagementEventObserver.Stub 203f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen public void interfaceStatusChanged(String name, boolean up) { 204f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen } 205f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen 206f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen // INetworkManagementEventObserver.Stub 207f59c7d0f2ac8d489b6d8118543a57ea4a603eacfMike J. Chen public void interfaceLinkStateChanged(String name, boolean up) { 208ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 209ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 210ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // INetworkManagementEventObserver.Stub 211ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh public void interfaceAdded(String name) { 212ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 213ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 214ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh // INetworkManagementEventObserver.Stub 215ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh public synchronized void interfaceRemoved(String name) { 216f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh if (name.equals(mInterfaceName) && jniCheckInterface(name) == 0) { 217ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh hideNotification(); 218ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mCallback.restore(); 219a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh mInterfaceName = null; 220ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 221ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 222ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 223a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh private void showNotification(VpnConfig config, String label, Bitmap icon) { 224ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh NotificationManager nm = (NotificationManager) 225ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext.getSystemService(Context.NOTIFICATION_SERVICE); 226ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 227ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (nm != null) { 228a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh String title = (label == null) ? mContext.getString(R.string.vpn_title) : 229a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh mContext.getString(R.string.vpn_title_long, label); 2307b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh String text = (config.sessionName == null) ? mContext.getString(R.string.vpn_text) : 2317b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh mContext.getString(R.string.vpn_text_long, config.sessionName); 232a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh 233ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh long identity = Binder.clearCallingIdentity(); 234ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh Notification notification = new Notification.Builder(mContext) 235ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .setSmallIcon(R.drawable.vpn_connected) 236a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh .setLargeIcon(icon) 237a4b87b5e980ffa52e9bc5549688b588b1b99a1ebChia-chi Yeh .setContentTitle(title) 238f8905fd13da0bfd6049daebc1cf4f8af286a04deChia-chi Yeh .setContentText(text) 2397b0b834c3d12564c44ac134879a6dbc70e74be6eChia-chi Yeh .setContentIntent(VpnConfig.getIntentForNotification(mContext, config)) 240ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .setDefaults(Notification.DEFAULT_ALL) 241ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .setOngoing(true) 242ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh .getNotification(); 243ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh nm.notify(R.drawable.vpn_connected, notification); 244ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh Binder.restoreCallingIdentity(identity); 245ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 246ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 247ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 248ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh private void hideNotification() { 249ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh NotificationManager nm = (NotificationManager) 250ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh mContext.getSystemService(Context.NOTIFICATION_SERVICE); 251ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 252ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh if (nm != null) { 253ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh long identity = Binder.clearCallingIdentity(); 254ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh nm.cancel(R.drawable.vpn_connected); 255ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh Binder.restoreCallingIdentity(identity); 256ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 257ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh } 258ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh 259f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh private native int jniCreateInterface(int mtu); 260f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh private native String jniGetInterfaceName(int fd); 261f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh private native int jniSetAddresses(String name, String addresses); 262f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh private native int jniSetRoutes(String name, String routes); 263f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh private native void jniResetInterface(String name); 264f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh private native int jniCheckInterface(String name); 265f4e3bf892e593d8c74290739446ac205fe8c66b2Chia-chi Yeh private native void jniProtectSocket(int fd, String name); 26685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 26785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 26885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * Handle legacy VPN requests. This method stops the services and restart 26985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * them if their arguments are not null. Heavy things are offloaded to 27085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * another thread, so callers will not be blocked too long. 27185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * 27285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * @param raoocn The arguments to be passed to racoon. 27385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * @param mtpd The arguments to be passed to mtpd. 27485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 27585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh public synchronized void doLegacyVpn(String[] racoon, String[] mtpd) { 27685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Currently only system user is allowed. 27785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (Binder.getCallingUid() != Process.SYSTEM_UID) { 27885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh throw new SecurityException("Unauthorized Caller"); 27985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 28085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 28185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // If the previous runner is still alive, interrupt it. 28285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (mLegacyVpnRunner != null && mLegacyVpnRunner.isAlive()) { 28385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mLegacyVpnRunner.interrupt(); 28485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 28585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 28685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Start a new runner and we are done! 28785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mLegacyVpnRunner = new LegacyVpnRunner( 28885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh new String[] {"racoon", "mtpd"}, racoon, mtpd); 28985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mLegacyVpnRunner.start(); 29085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 29185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 29285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh /** 29385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * Bringing up a VPN connection takes time, and that is all this thread 29485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * does. Here we have plenty of time. The only thing we need to take 29585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * care of is responding to interruptions as soon as possible. Otherwise 29685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * requests will be piled up. This can be done in a Handler as a state 29785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh * machine, but it is much easier to read in the current form. 29885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh */ 29985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private class LegacyVpnRunner extends Thread { 30085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private static final String TAG = "LegacyVpnRunner"; 30185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 30285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private static final String NONE = "--"; 30385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 30485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private final String[] mServices; 30585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private final String[][] mArguments; 30685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private long mTimer = -1; 30785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 30885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh public LegacyVpnRunner(String[] services, String[]... arguments) { 30985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh super(TAG); 31085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mServices = services; 31185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mArguments = arguments; 31285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 31385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 31485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh @Override 31585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh public void run() { 31685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the previous thread since it has been interrupted. 31785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Log.v(TAG, "wait"); 31885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh synchronized (TAG) { 31985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Log.v(TAG, "run"); 32085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh execute(); 32185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Log.v(TAG, "exit"); 32285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 32385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 32485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 32585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void checkpoint(boolean yield) throws InterruptedException { 32685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh long now = SystemClock.elapsedRealtime(); 32785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (mTimer == -1) { 32885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh mTimer = now; 32985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(1); 33085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } else if (now - mTimer <= 30000) { 33185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Thread.sleep(yield ? 200 : 1); 33285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } else { 33385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh throw new InterruptedException("timeout"); 33485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 33585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 33685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 33785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh private void execute() { 33885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Catch all exceptions so we can clean up few things. 33985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 34085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Initialize the timer. 34185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 34285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 34385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // First stop the services. 34485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String service : mServices) { 34585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh SystemProperties.set("ctl.stop", service); 34685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 34785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 34885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the services to stop. 34985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String service : mServices) { 35085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh String key = "init.svc." + service; 35185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (!"stopped".equals(SystemProperties.get(key))) { 35285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 35385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 35485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 35585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 35685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Reset the properties. 35785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh SystemProperties.set("vpn.dns", NONE); 35885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh SystemProperties.set("vpn.via", NONE); 35985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (!NONE.equals(SystemProperties.get("vpn.dns")) || 36085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh !NONE.equals(SystemProperties.get("vpn.via"))) { 36185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 36285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 36385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 36485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Check if we need to restart some services. 36585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh boolean restart = false; 36685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String[] arguments : mArguments) { 36785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh restart = restart || (arguments != null); 36885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 36985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (!restart) { 37085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh return; 37185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 37285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 37385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Start the service with arguments. 37485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (int i = 0; i < mServices.length; ++i) { 37585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh String[] arguments = mArguments[i]; 37685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (arguments == null) { 37785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh continue; 37885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 37985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 38085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Start the service. 38185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh String service = mServices[i]; 38285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh SystemProperties.set("ctl.start", service); 38385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 38485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the service to start. 38585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh String key = "init.svc." + service; 38685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (!"running".equals(SystemProperties.get(key))) { 38785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 38885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 38985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 39085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Create the control socket. 39185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh LocalSocket socket = new LocalSocket(); 39285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh LocalSocketAddress address = new LocalSocketAddress( 39385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh service, LocalSocketAddress.Namespace.RESERVED); 39485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 39585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Wait for the socket to connect. 39685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (true) { 39785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh try { 39885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh socket.connect(address); 39985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh break; 40085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 40185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // ignore 40285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 40385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 40485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 40585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh socket.setSoTimeout(500); 40685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 40785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Send over the arguments. 40885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh OutputStream output = socket.getOutputStream(); 40985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String argument : arguments) { 41085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh byte[] bytes = argument.getBytes(Charsets.UTF_8); 41185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (bytes.length >= 0xFFFF) { 41285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh throw new IllegalArgumentException("argument too large"); 41385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 41485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh output.write(bytes.length >> 8); 41585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh output.write(bytes.length); 41685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh output.write(bytes); 41785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(false); 41885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 41985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 42085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Send End-Of-Arguments. 42185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh output.write(0xFF); 42285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh output.write(0xFF); 42385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh output.flush(); 42485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh socket.close(); 42585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 42685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 42785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Now here is the beast from the old days. We check few 42885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // properties to figure out the current status. Ideally we 42985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // can read things back from the sockets and get rid of the 43085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // properties, but we have no time... 43185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh while (NONE.equals(SystemProperties.get("vpn.dns")) || 43285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh NONE.equals(SystemProperties.get("vpn.via"))) { 43385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 43485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Check if a running service is dead. 43585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (int i = 0; i < mServices.length; ++i) { 43685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh String service = mServices[i]; 43785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh if (mArguments[i] != null && !"running".equals( 43885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh SystemProperties.get("init.svc." + service))) { 43985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh throw new IllegalArgumentException(service + " is dead"); 44085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 44185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 44285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh checkpoint(true); 44385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 44485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 44585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // Great! Now we are connected! 44685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Log.i(TAG, "connected!"); 44785a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh // TODO: 44885a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh 44985a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } catch (Exception e) { 45085a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh Log.i(TAG, e.getMessage()); 45185a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh for (String service : mServices) { 45285a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh SystemProperties.set("ctl.stop", service); 45385a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 45485a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 45585a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 45685a7ce02c8b53e1efaa5a3a32f0a5ec7b549f758Chia-chi Yeh } 457ff3bdca31f4cf2bd607519b276dd175763aa1784Chia-chi Yeh} 458