1 /* 2 * Copyright (C) 2009, 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 17 package com.android.server.vpn; 18 19 import android.app.Service; 20 import android.content.Intent; 21 import android.net.vpn.IVpnService; 22 import android.net.vpn.L2tpIpsecProfile; 23 import android.net.vpn.L2tpIpsecPskProfile; 24 import android.net.vpn.L2tpProfile; 25 import android.net.vpn.PptpProfile; 26 import android.net.vpn.VpnManager; 27 import android.net.vpn.VpnProfile; 28 import android.net.vpn.VpnState; 29 import android.os.Environment; 30 import android.os.IBinder; 31 import android.os.SystemProperties; 32 import android.util.Log; 33 34 import java.io.File; 35 import java.io.FileInputStream; 36 import java.io.FileNotFoundException; 37 import java.io.FileOutputStream; 38 import java.io.IOException; 39 import java.io.ObjectInputStream; 40 import java.io.ObjectOutputStream; 41 42 /** 43 * The service class for managing a VPN connection. It implements the 44 * {@link IVpnService} binder interface. 45 */ 46 public class VpnServiceBinder extends Service { 47 private static final String TAG = VpnServiceBinder.class.getSimpleName(); 48 private static final boolean DBG = true; 49 50 private static final String STATES_FILE_RELATIVE_PATH = "/misc/vpn/.states"; 51 52 // The actual implementation is delegated to the VpnService class. 53 private VpnService<? extends VpnProfile> mService; 54 55 private static String getStateFilePath() { 56 return Environment.getDataDirectory().getPath() + STATES_FILE_RELATIVE_PATH; 57 } 58 59 private final IBinder mBinder = new IVpnService.Stub() { 60 public boolean connect(VpnProfile p, String username, String password) { 61 return VpnServiceBinder.this.connect(p, username, password); 62 } 63 64 public void disconnect() { 65 VpnServiceBinder.this.disconnect(); 66 } 67 68 public void checkStatus(VpnProfile p) { 69 VpnServiceBinder.this.checkStatus(p); 70 } 71 }; 72 73 @Override 74 public void onCreate() { 75 super.onCreate(); 76 checkSavedStates(); 77 } 78 79 80 @Override 81 public void onStart(Intent intent, int startId) { 82 super.onStart(intent, startId); 83 } 84 85 @Override 86 public IBinder onBind(Intent intent) { 87 return mBinder; 88 } 89 90 void saveStates() throws IOException { 91 if (DBG) Log.d("VpnServiceBinder", " saving states"); 92 ObjectOutputStream oos = 93 new ObjectOutputStream(new FileOutputStream(getStateFilePath())); 94 oos.writeObject(mService); 95 oos.close(); 96 } 97 98 void removeStates() { 99 try { 100 File f = new File(getStateFilePath()); 101 if (f.exists()) f.delete(); 102 } catch (Throwable e) { 103 if (DBG) Log.d("VpnServiceBinder", " remove states: " + e); 104 } 105 } 106 107 private synchronized boolean connect(final VpnProfile p, 108 final String username, final String password) { 109 if (mService != null) return false; 110 final VpnService s = mService = createService(p); 111 112 new Thread(new Runnable() { 113 public void run() { 114 s.onConnect(username, password); 115 } 116 }).start(); 117 return true; 118 } 119 120 private synchronized void disconnect() { 121 if (mService == null) return; 122 final VpnService s = mService; 123 124 new Thread(new Runnable() { 125 public void run() { 126 s.onDisconnect(); 127 } 128 }).start(); 129 } 130 131 private synchronized void checkStatus(VpnProfile p) { 132 if ((mService == null) 133 || (!p.getName().equals(mService.mProfile.getName()))) { 134 broadcastConnectivity(p.getName(), VpnState.IDLE); 135 } else { 136 broadcastConnectivity(p.getName(), mService.getState()); 137 } 138 } 139 140 private void checkSavedStates() { 141 try { 142 ObjectInputStream ois = new ObjectInputStream(new FileInputStream( 143 getStateFilePath())); 144 mService = (VpnService<? extends VpnProfile>) ois.readObject(); 145 mService.recover(this); 146 ois.close(); 147 } catch (FileNotFoundException e) { 148 // do nothing 149 } catch (Throwable e) { 150 Log.i("VpnServiceBinder", "recovery error, remove states: " + e); 151 removeStates(); 152 } 153 } 154 155 private VpnService<? extends VpnProfile> createService(VpnProfile p) { 156 switch (p.getType()) { 157 case L2TP: 158 L2tpService l2tp = new L2tpService(); 159 l2tp.setContext(this, (L2tpProfile) p); 160 return l2tp; 161 162 case PPTP: 163 PptpService pptp = new PptpService(); 164 pptp.setContext(this, (PptpProfile) p); 165 return pptp; 166 167 case L2TP_IPSEC_PSK: 168 L2tpIpsecPskService psk = new L2tpIpsecPskService(); 169 psk.setContext(this, (L2tpIpsecPskProfile) p); 170 return psk; 171 172 case L2TP_IPSEC: 173 L2tpIpsecService l2tpIpsec = new L2tpIpsecService(); 174 l2tpIpsec.setContext(this, (L2tpIpsecProfile) p); 175 return l2tpIpsec; 176 177 default: 178 return null; 179 } 180 } 181 182 private void broadcastConnectivity(String name, VpnState s) { 183 new VpnManager(this).broadcastConnectivity(name, s); 184 } 185 } 186