blob: a8be916427f39ede840398ee5d38ff8d0fe1b2e9 [file] [log] [blame]
Chia-chi Yehff3bdca2011-05-23 17:26:46 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.connectivity;
18
19import android.app.Notification;
20import android.app.NotificationManager;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070021import android.content.Context;
22import android.content.Intent;
23import android.content.pm.ApplicationInfo;
24import android.content.pm.PackageManager;
25import android.content.res.Resources;
26import android.graphics.Bitmap;
27import android.graphics.Canvas;
28import android.graphics.drawable.Drawable;
29import android.net.INetworkManagementEventObserver;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070030import android.net.LocalSocket;
31import android.net.LocalSocketAddress;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070032import android.os.Binder;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070033import android.os.ParcelFileDescriptor;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070034import android.os.Process;
35import android.os.SystemClock;
36import android.os.SystemProperties;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070037import android.util.Log;
38
39import com.android.internal.R;
Chia-chi Yeh04ba25c2011-06-15 17:07:27 -070040import com.android.internal.net.VpnConfig;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070041import com.android.server.ConnectivityService.VpnCallback;
42
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070043import java.io.OutputStream;
44import java.nio.charset.Charsets;
Chia-chi Yeh41d16852011-07-01 02:12:06 -070045import java.util.Arrays;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070046
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070047/**
48 * @hide
49 */
50public class Vpn extends INetworkManagementEventObserver.Stub {
51
52 private final static String TAG = "Vpn";
53 private final static String VPN = android.Manifest.permission.VPN;
54
55 private final Context mContext;
56 private final VpnCallback mCallback;
57
58 private String mPackageName;
59 private String mInterfaceName;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -070060
61 private LegacyVpnRunner mLegacyVpnRunner;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070062
63 public Vpn(Context context, VpnCallback callback) {
64 mContext = context;
65 mCallback = callback;
66 }
67
68 /**
69 * Prepare for a VPN application.
70 *
71 * @param packageName The package name of the new VPN application.
72 * @return The name of the current prepared package.
73 */
74 public synchronized String prepare(String packageName) {
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -070075 // Return the current prepared package if the new one is null.
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070076 if (packageName == null) {
77 return mPackageName;
78 }
79
Chia-chi Yeh41d16852011-07-01 02:12:06 -070080 // Only system user can call this method.
81 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
82 throw new SecurityException("Unauthorized Caller");
83 }
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -070084
85 // Check the permission of the given package.
Chia-chi Yeh41d16852011-07-01 02:12:06 -070086 PackageManager pm = mContext.getPackageManager();
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -070087 if (packageName.isEmpty()) {
88 packageName = null;
89 } else if (pm.checkPermission(VPN, packageName) != PackageManager.PERMISSION_GRANTED) {
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070090 throw new SecurityException(packageName + " does not have " + VPN);
91 }
92
93 // Reset the interface and hide the notification.
94 if (mInterfaceName != null) {
Chia-chi Yehf4e3bf82011-06-30 12:33:17 -070095 jniResetInterface(mInterfaceName);
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -070096 mCallback.restore();
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070097 hideNotification();
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -070098 mInterfaceName = null;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -070099 }
100
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -0700101 // Notify the package being revoked.
102 if (mPackageName != null) {
103 Intent intent = new Intent(VpnConfig.ACTION_VPN_REVOKED);
104 intent.setPackage(mPackageName);
105 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
106 mContext.sendBroadcast(intent);
107 }
108
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700109 // Stop legacy VPN if it has been started.
110 if (mLegacyVpnRunner != null) {
111 mLegacyVpnRunner.exit();
112 mLegacyVpnRunner = null;
113 }
114
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -0700115 Log.i(TAG, "Switched from " + mPackageName + " to " + packageName);
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700116 mPackageName = packageName;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700117 return mPackageName;
118 }
119
120 /**
121 * Protect a socket from routing changes by binding it to the given
Chia-chi Yeh3f3337a2011-06-17 16:34:32 -0700122 * interface. The socket IS closed by this method.
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700123 *
124 * @param socket The socket to be bound.
125 * @param name The name of the interface.
126 */
127 public void protect(ParcelFileDescriptor socket, String name) {
Chia-chi Yeh3f3337a2011-06-17 16:34:32 -0700128 try {
129 mContext.enforceCallingPermission(VPN, "protect");
Chia-chi Yehf4e3bf82011-06-30 12:33:17 -0700130 jniProtectSocket(socket.getFd(), name);
Chia-chi Yeh3f3337a2011-06-17 16:34:32 -0700131 } finally {
132 try {
133 socket.close();
134 } catch (Exception e) {
135 // ignore
136 }
137 }
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700138 }
139
140 /**
141 * Configure a TUN interface and return its file descriptor.
142 *
Chia-chi Yeha4b87b52011-06-30 23:21:55 -0700143 * @param config The parameters to configure the interface.
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700144 * @return The file descriptor of the interface.
145 */
Chia-chi Yeh04ba25c2011-06-15 17:07:27 -0700146 public synchronized ParcelFileDescriptor establish(VpnConfig config) {
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700147 // Check the permission of the caller.
148 mContext.enforceCallingPermission(VPN, "establish");
149
150 // Check if the caller is already prepared.
151 PackageManager pm = mContext.getPackageManager();
152 ApplicationInfo app = null;
153 try {
154 app = pm.getApplicationInfo(mPackageName, 0);
155 } catch (Exception e) {
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -0700156 return null;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700157 }
158 if (Binder.getCallingUid() != app.uid) {
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -0700159 return null;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700160 }
161
Chia-chi Yeha4b87b52011-06-30 23:21:55 -0700162 // Load the label.
163 String label = app.loadLabel(pm).toString();
164
165 // Load the icon and convert it into a bitmap.
166 Drawable icon = app.loadIcon(pm);
167 Bitmap bitmap = null;
168 if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) {
169 int width = mContext.getResources().getDimensionPixelSize(
170 android.R.dimen.notification_large_icon_width);
171 int height = mContext.getResources().getDimensionPixelSize(
172 android.R.dimen.notification_large_icon_height);
173 icon.setBounds(0, 0, width, height);
174 bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
175 icon.draw(new Canvas(bitmap));
176 }
177
178 // Create the interface and abort if any of the following steps fails.
Chia-chi Yehf4e3bf82011-06-30 12:33:17 -0700179 ParcelFileDescriptor descriptor =
180 ParcelFileDescriptor.adoptFd(jniCreateInterface(config.mtu));
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700181 try {
Chia-chi Yehf4e3bf82011-06-30 12:33:17 -0700182 String name = jniGetInterfaceName(descriptor.getFd());
183 if (jniSetAddresses(name, config.addresses) < 1) {
184 throw new IllegalArgumentException("At least one address must be specified");
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700185 }
Chia-chi Yehf4e3bf82011-06-30 12:33:17 -0700186 if (config.routes != null) {
187 jniSetRoutes(name, config.routes);
188 }
189 if (mInterfaceName != null && !mInterfaceName.equals(name)) {
190 jniResetInterface(mInterfaceName);
191 }
192 mInterfaceName = name;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700193 } catch (RuntimeException e) {
194 try {
195 descriptor.close();
196 } catch (Exception ex) {
197 // ignore
198 }
199 throw e;
200 }
201
Chia-chi Yeh8909b102011-07-01 01:09:42 -0700202 // Override DNS servers and search domains.
203 mCallback.override(config.dnsServers, config.searchDomains);
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700204
Chia-chi Yeh8909b102011-07-01 01:09:42 -0700205 // Fill more values.
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -0700206 config.packageName = mPackageName;
207 config.interfaceName = mInterfaceName;
Chia-chi Yeh8909b102011-07-01 01:09:42 -0700208
209 // Show the notification!
Chia-chi Yeh383e0522011-07-01 00:13:25 -0700210 showNotification(config, label, bitmap);
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700211 return descriptor;
212 }
213
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700214 // INetworkManagementEventObserver.Stub
Mike J. Chenf59c7d02011-06-23 15:33:15 -0700215 public void interfaceStatusChanged(String name, boolean up) {
216 }
217
218 // INetworkManagementEventObserver.Stub
219 public void interfaceLinkStateChanged(String name, boolean up) {
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700220 }
221
222 // INetworkManagementEventObserver.Stub
223 public void interfaceAdded(String name) {
224 }
225
226 // INetworkManagementEventObserver.Stub
227 public synchronized void interfaceRemoved(String name) {
Chia-chi Yehf4e3bf82011-06-30 12:33:17 -0700228 if (name.equals(mInterfaceName) && jniCheckInterface(name) == 0) {
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700229 hideNotification();
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700230 mCallback.restore();
Chia-chi Yeha4b87b52011-06-30 23:21:55 -0700231 mInterfaceName = null;
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700232 }
233 }
234
Chia-chi Yeha4b87b52011-06-30 23:21:55 -0700235 private void showNotification(VpnConfig config, String label, Bitmap icon) {
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700236 NotificationManager nm = (NotificationManager)
237 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
238
239 if (nm != null) {
Chia-chi Yeha4b87b52011-06-30 23:21:55 -0700240 String title = (label == null) ? mContext.getString(R.string.vpn_title) :
241 mContext.getString(R.string.vpn_title_long, label);
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -0700242 String text = (config.sessionName == null) ? mContext.getString(R.string.vpn_text) :
243 mContext.getString(R.string.vpn_text_long, config.sessionName);
Chia-chi Yeha4b87b52011-06-30 23:21:55 -0700244
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700245 long identity = Binder.clearCallingIdentity();
246 Notification notification = new Notification.Builder(mContext)
247 .setSmallIcon(R.drawable.vpn_connected)
Chia-chi Yeha4b87b52011-06-30 23:21:55 -0700248 .setLargeIcon(icon)
249 .setContentTitle(title)
Chia-chi Yehf8905fd2011-06-14 16:35:02 -0700250 .setContentText(text)
Chia-chi Yeh7b0b8342011-06-17 14:34:11 -0700251 .setContentIntent(VpnConfig.getIntentForNotification(mContext, config))
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700252 .setDefaults(Notification.DEFAULT_ALL)
253 .setOngoing(true)
254 .getNotification();
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700255 nm.notify(R.drawable.vpn_connected, notification);
256 Binder.restoreCallingIdentity(identity);
257 }
258 }
259
260 private void hideNotification() {
261 NotificationManager nm = (NotificationManager)
262 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
263
264 if (nm != null) {
265 long identity = Binder.clearCallingIdentity();
266 nm.cancel(R.drawable.vpn_connected);
267 Binder.restoreCallingIdentity(identity);
268 }
269 }
270
Chia-chi Yehf4e3bf82011-06-30 12:33:17 -0700271 private native int jniCreateInterface(int mtu);
272 private native String jniGetInterfaceName(int fd);
273 private native int jniSetAddresses(String name, String addresses);
274 private native int jniSetRoutes(String name, String routes);
275 private native void jniResetInterface(String name);
276 private native int jniCheckInterface(String name);
277 private native void jniProtectSocket(int fd, String name);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700278
279 /**
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700280 * Handle legacy VPN requests. This method stops the daemons and restart
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700281 * them if their arguments are not null. Heavy things are offloaded to
282 * another thread, so callers will not be blocked too long.
283 *
284 * @param raoocn The arguments to be passed to racoon.
285 * @param mtpd The arguments to be passed to mtpd.
286 */
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700287 public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
288 // Stop the current VPN just like a normal VPN application.
289 prepare("");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700290
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700291 // Legacy VPN does not have a package name.
292 config.packageName = null;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700293
294 // Start a new runner and we are done!
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700295 mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700296 mLegacyVpnRunner.start();
297 }
298
299 /**
300 * Bringing up a VPN connection takes time, and that is all this thread
301 * does. Here we have plenty of time. The only thing we need to take
302 * care of is responding to interruptions as soon as possible. Otherwise
303 * requests will be piled up. This can be done in a Handler as a state
304 * machine, but it is much easier to read in the current form.
305 */
306 private class LegacyVpnRunner extends Thread {
307 private static final String TAG = "LegacyVpnRunner";
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700308 private static final String NONE = "--";
309
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700310 private final VpnConfig mConfig;
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700311 private final String[] mDaemons;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700312 private final String[][] mArguments;
313 private long mTimer = -1;
314
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700315 public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) {
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700316 super(TAG);
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700317 mConfig = config;
318 mDaemons = new String[] {"racoon", "mtpd"};
319 mArguments = new String[][] {racoon, mtpd};
320 }
321
322 public void exit() {
323 for (String daemon : mDaemons) {
324 SystemProperties.set("ctl.stop", daemon);
325 }
326 interrupt();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700327 }
328
329 @Override
330 public void run() {
331 // Wait for the previous thread since it has been interrupted.
332 Log.v(TAG, "wait");
333 synchronized (TAG) {
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700334 Log.v(TAG, "begin");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700335 execute();
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700336 Log.v(TAG, "end");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700337 }
338 }
339
340 private void checkpoint(boolean yield) throws InterruptedException {
341 long now = SystemClock.elapsedRealtime();
342 if (mTimer == -1) {
343 mTimer = now;
344 Thread.sleep(1);
345 } else if (now - mTimer <= 30000) {
346 Thread.sleep(yield ? 200 : 1);
347 } else {
348 throw new InterruptedException("timeout");
349 }
350 }
351
352 private void execute() {
353 // Catch all exceptions so we can clean up few things.
354 try {
355 // Initialize the timer.
356 checkpoint(false);
357
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700358 // First stop the daemons.
359 for (String daemon : mDaemons) {
360 SystemProperties.set("ctl.stop", daemon);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700361 }
362
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700363 // Wait for the daemons to stop.
364 for (String daemon : mDaemons) {
365 String key = "init.svc." + daemon;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700366 while (!"stopped".equals(SystemProperties.get(key))) {
367 checkpoint(true);
368 }
369 }
370
371 // Reset the properties.
372 SystemProperties.set("vpn.dns", NONE);
373 SystemProperties.set("vpn.via", NONE);
374 while (!NONE.equals(SystemProperties.get("vpn.dns")) ||
375 !NONE.equals(SystemProperties.get("vpn.via"))) {
376 checkpoint(true);
377 }
378
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700379 // Check if we need to restart some daemons.
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700380 boolean restart = false;
381 for (String[] arguments : mArguments) {
382 restart = restart || (arguments != null);
383 }
384 if (!restart) {
385 return;
386 }
387
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700388 // Start the daemon with arguments.
389 for (int i = 0; i < mDaemons.length; ++i) {
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700390 String[] arguments = mArguments[i];
391 if (arguments == null) {
392 continue;
393 }
394
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700395 // Start the daemon.
396 String daemon = mDaemons[i];
397 SystemProperties.set("ctl.start", daemon);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700398
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700399 // Wait for the daemon to start.
400 String key = "init.svc." + daemon;
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700401 while (!"running".equals(SystemProperties.get(key))) {
402 checkpoint(true);
403 }
404
405 // Create the control socket.
406 LocalSocket socket = new LocalSocket();
407 LocalSocketAddress address = new LocalSocketAddress(
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700408 daemon, LocalSocketAddress.Namespace.RESERVED);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700409
410 // Wait for the socket to connect.
411 while (true) {
412 try {
413 socket.connect(address);
414 break;
415 } catch (Exception e) {
416 // ignore
417 }
418 checkpoint(true);
419 }
420 socket.setSoTimeout(500);
421
422 // Send over the arguments.
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700423 OutputStream out = socket.getOutputStream();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700424 for (String argument : arguments) {
425 byte[] bytes = argument.getBytes(Charsets.UTF_8);
426 if (bytes.length >= 0xFFFF) {
427 throw new IllegalArgumentException("argument too large");
428 }
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700429 out.write(bytes.length >> 8);
430 out.write(bytes.length);
431 out.write(bytes);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700432 checkpoint(false);
433 }
434
435 // Send End-Of-Arguments.
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700436 out.write(0xFF);
437 out.write(0xFF);
438 out.flush();
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700439 socket.close();
440 }
441
442 // Now here is the beast from the old days. We check few
443 // properties to figure out the current status. Ideally we
444 // can read things back from the sockets and get rid of the
445 // properties, but we have no time...
446 while (NONE.equals(SystemProperties.get("vpn.dns")) ||
447 NONE.equals(SystemProperties.get("vpn.via"))) {
448
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700449 // Check if a running daemon is dead.
450 for (int i = 0; i < mDaemons.length; ++i) {
451 String daemon = mDaemons[i];
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700452 if (mArguments[i] != null && !"running".equals(
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700453 SystemProperties.get("init.svc." + daemon))) {
454 throw new IllegalArgumentException(daemon + " is dead");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700455 }
456 }
457 checkpoint(true);
458 }
459
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700460 // Now we are connected. Get the interface.
461 mConfig.interfaceName = SystemProperties.get("vpn.via");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700462
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700463 // Get the DNS servers if they are not set in config.
464 if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
465 String dnsServers = SystemProperties.get("vpn.dns").trim();
466 if (!dnsServers.isEmpty()) {
467 mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
468 }
469 }
470
471 // TODO: support routes and search domains for IPSec Mode-CFG.
472
473 // This is it! Here is the end of our journey!
474 synchronized (Vpn.this) {
475 // Check if the thread is interrupted while we are waiting.
476 checkpoint(false);
477
478 if (mConfig.routes != null) {
479 jniSetRoutes(mConfig.interfaceName, mConfig.routes);
480 }
481 mInterfaceName = mConfig.interfaceName;
482 mCallback.override(mConfig.dnsServers, mConfig.searchDomains);
483 showNotification(mConfig, null, null);
484 }
485 Log.i(TAG, "Connected!");
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700486 } catch (Exception e) {
Chia-chi Yeh41d16852011-07-01 02:12:06 -0700487 Log.i(TAG, "Abort due to " + e.getMessage());
Chia-chi Yeh1f7746b2011-07-01 00:29:06 -0700488 for (String daemon : mDaemons) {
489 SystemProperties.set("ctl.stop", daemon);
Chia-chi Yeh85a7ce02011-06-29 16:05:58 -0700490 }
491 }
492 }
493 }
Chia-chi Yehff3bdca2011-05-23 17:26:46 -0700494}