Home | History | Annotate | Download | only in vpn
      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     // TODO(oam): Test VPN when EFS is enabled (will do later)...
     56     private static String getStateFilePath() {
     57         // This call will return the correcu directory whether Encrypted FS is enabled or not
     58         // Disabled: /data/misc/vpn/.states   Enabled: /data/secure/misc/vpn/.states
     59 	return Environment.getSecureDataDirectory().getPath() + STATES_FILE_RELATIVE_PATH;
     60     }
     61 
     62     private final IBinder mBinder = new IVpnService.Stub() {
     63         public boolean connect(VpnProfile p, String username, String password) {
     64             return VpnServiceBinder.this.connect(p, username, password);
     65         }
     66 
     67         public void disconnect() {
     68             VpnServiceBinder.this.disconnect();
     69         }
     70 
     71         public void checkStatus(VpnProfile p) {
     72             VpnServiceBinder.this.checkStatus(p);
     73         }
     74     };
     75 
     76     @Override
     77     public void onCreate() {
     78         super.onCreate();
     79         checkSavedStates();
     80     }
     81 
     82 
     83     @Override
     84     public void onStart(Intent intent, int startId) {
     85         super.onStart(intent, startId);
     86     }
     87 
     88     @Override
     89     public IBinder onBind(Intent intent) {
     90         return mBinder;
     91     }
     92 
     93     void saveStates() throws IOException {
     94         if (DBG) Log.d("VpnServiceBinder", "     saving states");
     95         ObjectOutputStream oos =
     96                 new ObjectOutputStream(new FileOutputStream(getStateFilePath()));
     97         oos.writeObject(mService);
     98         oos.close();
     99     }
    100 
    101     void removeStates() {
    102         try {
    103             File f = new File(getStateFilePath());
    104             if (f.exists()) f.delete();
    105         } catch (Throwable e) {
    106             if (DBG) Log.d("VpnServiceBinder", "     remove states: " + e);
    107         }
    108     }
    109 
    110     private synchronized boolean connect(final VpnProfile p,
    111             final String username, final String password) {
    112         if (mService != null) return false;
    113         final VpnService s = mService = createService(p);
    114 
    115         new Thread(new Runnable() {
    116             public void run() {
    117                 s.onConnect(username, password);
    118             }
    119         }).start();
    120         return true;
    121     }
    122 
    123     private synchronized void disconnect() {
    124         if (mService == null) return;
    125         final VpnService s = mService;
    126 
    127         new Thread(new Runnable() {
    128             public void run() {
    129                 s.onDisconnect();
    130             }
    131         }).start();
    132     }
    133 
    134     private synchronized void checkStatus(VpnProfile p) {
    135         if ((mService == null)
    136                 || (!p.getName().equals(mService.mProfile.getName()))) {
    137             broadcastConnectivity(p.getName(), VpnState.IDLE);
    138         } else {
    139             broadcastConnectivity(p.getName(), mService.getState());
    140         }
    141     }
    142 
    143     private void checkSavedStates() {
    144         try {
    145             ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
    146                     getStateFilePath()));
    147             mService = (VpnService<? extends VpnProfile>) ois.readObject();
    148             mService.recover(this);
    149             ois.close();
    150         } catch (FileNotFoundException e) {
    151             // do nothing
    152         } catch (Throwable e) {
    153             Log.i("VpnServiceBinder", "recovery error, remove states: " + e);
    154             removeStates();
    155         }
    156     }
    157 
    158     private VpnService<? extends VpnProfile> createService(VpnProfile p) {
    159         switch (p.getType()) {
    160             case L2TP:
    161                 L2tpService l2tp = new L2tpService();
    162                 l2tp.setContext(this, (L2tpProfile) p);
    163                 return l2tp;
    164 
    165             case PPTP:
    166                 PptpService pptp = new PptpService();
    167                 pptp.setContext(this, (PptpProfile) p);
    168                 return pptp;
    169 
    170             case L2TP_IPSEC_PSK:
    171                 L2tpIpsecPskService psk = new L2tpIpsecPskService();
    172                 psk.setContext(this, (L2tpIpsecPskProfile) p);
    173                 return psk;
    174 
    175             case L2TP_IPSEC:
    176                 L2tpIpsecService l2tpIpsec = new L2tpIpsecService();
    177                 l2tpIpsec.setContext(this, (L2tpIpsecProfile) p);
    178                 return l2tpIpsec;
    179 
    180             default:
    181                 return null;
    182         }
    183     }
    184 
    185     private void broadcastConnectivity(String name, VpnState s) {
    186         new VpnManager(this).broadcastConnectivity(name, s);
    187     }
    188 }
    189