Android Open Source - azilink Forward Service






From Project

Back to project page azilink.

License

The source code is released under:

GNU General Public License

If you think the Android project azilink listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/* AziLink: USB tethering for Android
 * Copyright (C) 2009 by James Perry//from  w  w  w .j ava  2 s.  com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.lfx.azilink;

import java.io.IOException;

import org.lfx.azilink.net.VpnNatEngine;
import org.lfx.azilink.net.VpnNatEngineNotify;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.util.Log;

/**
 * Controls the VPN service and sends statistics back to the UI.  This service runs in a different
 * process space than the UI to protect the network code from UI crashes.
 * 
 * @author Jim Perry
 *
 */
public class ForwardService extends Service implements VpnNatEngineNotify {
  /** The actual NAT engine. */
  VpnNatEngine mEngine;          

  /** If WiFi is active when VPN link is started, then hold a WiFi lock to keep
   * the WiFi connection active.
   */
  WifiManager.WifiLock mWifiLock;
  
  /** Is a computer connected to the VPN? */
  boolean mActive = false;  
  
  /** Bytes received prior to the last mark point. */
  private long mBytesSavedRecv = 0;
  /** Bytes sent prior to the last mark point. */
  private long mBytesSavedSent = 0;
  /** How often should we save the byte counters to a file (ms)? */
  private static final int sPeriodicSaveTime = 30000;
  /** Handler which periodically saves the byte counters */
  Handler mHandler = new Handler();
  /** Enable debug logging. */
  final static boolean sLog = false;
  
  /**
   * Start the VPN engine.  Called when the user clicks "start service."
   */
  @Override
  public void onCreate() {
    super.onCreate();
    
    if(sLog) Log.v("AziLink", "fwd::onCreate");
    SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
    mBytesSavedSent = pref.getLong(getString(R.string.pref_key_saved_bytessent), 0);
    mBytesSavedRecv = pref.getLong(getString(R.string.pref_key_saved_bytesrecv), 0);
                
    mEngine = new VpnNatEngine( this );
    mEngine.setTMobileWorkaround(pref.getBoolean(getString(R.string.pref_key_tmobile),false));
    mEngine.setTMobileWorkaroundTimeout(Integer.parseInt(pref.getString(getString(R.string.pref_key_tmobile_ms),"1000")));
    mEngine.setPinger(pref.getBoolean(getString(R.string.pref_key_ping),true));
    try {
      mEngine.start();
    } catch (IOException e) {
      onError( e.toString() );
      return;
    }
    
    WifiManager wifi = (WifiManager) getSystemService(WIFI_SERVICE);
    mWifiLock = wifi.createWifiLock("AziLink");
    mWifiLock.setReferenceCounted(false);
    
    // Probably don't need to hold the power lock since this is a USB service and
    // the phone never suspends while it's plugged in..
    //
    // mPower = (PowerManager) getSystemService( Context.POWER_SERVICE );
    // mPowerLock = mPower.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, "AziLink" );    

    Notification not = new Notification(R.drawable.notify, getString(R.string.notify), 0);
    
    CharSequence contentTitle = getString(R.string.notify);
    CharSequence contentText = "";
    Intent notificationIntent = new Intent(this, MainActivity.class);
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    
    not.setLatestEventInfo(this, contentTitle, contentText, contentIntent);
    not.flags = Notification.FLAG_NO_CLEAR |
          Notification.FLAG_ONGOING_EVENT;

    Reflection.startForeground(this, not);
  }
  
  /**
   * Shut down the VPN engine, save byte counters, and release any WiFi locks.
   */
  @Override
  public void onDestroy() {
    if(sLog) Log.v("AziLink", "fwd::onDestroy");
    try {
      mWifiLock.release();
      mEngine.stop();
      saveByteCounters();
    } catch (InterruptedException e) {
      onError( e.toString() );
    }
    Reflection.stopForeground(this);
    super.onDestroy();
  }
  
  /**
   * Save the byte counters to disk, and zero the dynamic counters inside the VPN module.
   * Actual usage is saved_value + dynamic_value
   */
  public void saveByteCounters() {
    if(sLog) Log.v("AziLink", "fwd::saveByteCounters");
    mBytesSavedSent += mEngine.getBytesSent();
    mBytesSavedRecv += mEngine.getBytesRecv();    
    
    SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
    SharedPreferences.Editor ed = pref.edit();
    ed.putLong(getString(R.string.pref_key_saved_bytessent), mBytesSavedSent);
    ed.putLong(getString(R.string.pref_key_saved_bytesrecv), mBytesSavedRecv);
    ed.commit();        
    
    mEngine.resetCounters();
  }
    
  /**
   * Callback from VPN module indicating VPN link is active.  Grabs the WiFi lock, and
   * changes the service priority to foreground.
   */
  public void onLinkEstablished() {
    Log.v("AziLink", "AziLink established connection to VPN");
    mWifiLock.acquire();
    mActive = true;
    mPeriodicSaver.run();
    
    //mPowerLock.acquire();
  }
  
  /**
   * Callback from VPN module indicating VPN link has been lost.  Releases WiFi lock,
   * removes the periodic byte counter saver, and indicates whether the NAT module should
   * terminate all connections.
   * 
   * @return whether the NAT module should close all connections
   */
  public boolean onLinkLost() {
    Log.v("AziLink", "AziLink lost connection to VPN");
    mWifiLock.release();
    mActive = false;
    mPeriodicSaver.run();
    
    SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
    return pref.getBoolean(getString(R.string.pref_key_autodisconnect),true);
        //mPowerLock.release();
  }
  
  /**
   * Periodically saves the byte counters to disk.
   */
  Runnable mPeriodicSaver = new Runnable() {
    public void run() {
      saveByteCounters();
      if( mActive ) {
        mHandler.removeCallbacks(this);
        mHandler.postDelayed(this, sPeriodicSaveTime);
      }
    }    
  };
  
  /**
   * Display an error to the user.
   * @param error Error message
   */
  public void onError( String error ) {
    Log.e("AziLink","***** AZILINK CRASH ******: "+error);
    NotificationManager nm = (NotificationManager) getSystemService( NOTIFICATION_SERVICE );
    Notification n = new Notification(R.drawable.icon, getText(R.string.error_desc), System.currentTimeMillis() );
    PendingIntent contentIntent = PendingIntent.getActivity(ForwardService.this, 0, 
        new Intent(ForwardService.this, MainActivity.class), 0);
    n.setLatestEventInfo(ForwardService.this, getText(R.string.error_label), getText(R.string.error_desc), contentIntent);
    nm.notify(R.string.error_label, n); 
  }

  @Override
  public IBinder onBind(Intent intent) {
    if(sLog) Log.v("AziLink", "fwd::onBind");
    return mBinder;
  }

  /**
   * Implements the interface for communication between the service and the UI module.
   */
  private final IAziLinkInformation.Stub mBinder = new IAziLinkInformation.Stub() {

    /**
     * Retrieves statistics about the VPN link and returns them to the UI.
     * @return link statistics
     */
    public LinkStatistics getStatistics() throws RemoteException {
      if(sLog) Log.v("AziLink", "fwd::getStatistics");
      LinkStatistics ls = new LinkStatistics();
      ls.mBytesRecv = mEngine.getBytesRecv() + mBytesSavedRecv;
      ls.mBytesSent = mEngine.getBytesSent() + mBytesSavedSent;
      ls.mBytesTotal = ls.mBytesRecv + ls.mBytesSent;
      ls.mTcpConnections = mEngine.getTcpSize();
      ls.mUdpConnections = mEngine.getUdpSize();
      if( mActive ) {
        ls.mStatus = getString(R.string.status_active);
      } else {
        ls.mStatus = getString(R.string.status_listen);
      }
      return ls;
    }

    /**
     * Zeros all the byte counters.
     */
    public void resetCounters() throws RemoteException {
      mBytesSavedSent = 0;
      mBytesSavedRecv = 0;    
      if(sLog) Log.v("AziLink", "fwd::reset");
      
      SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(ForwardService.this);
      SharedPreferences.Editor ed = pref.edit();
      ed.putLong(getString(R.string.pref_key_saved_bytessent), mBytesSavedSent);
      ed.putLong(getString(R.string.pref_key_saved_bytesrecv), mBytesSavedRecv);
      ed.commit();        
      
      mEngine.resetCounters();
    }

    /**
     * Dynamically activates the T-Mobile workaround.
     * @param active whether the workaround is active.
     */
    public void setTMworkaround(boolean active) throws RemoteException {
      if(sLog) Log.v("AziLink", "fwd::setTM");
      mEngine.setTMobileWorkaround(active);
    }

    /**
     * Dynamically changes the timeout for the T-Mobile workaround.
     * @param ms how long to stall connections.
     */
    public void setTMworkaroundTimeout(int ms) throws RemoteException {
      if(sLog) Log.v("AziLink", "fwd::setTM");
      mEngine.setTMobileWorkaroundTimeout(ms);
    }
    
    /**
     * Dynamically change whether a VPN link will be terminated when
     * the connection has been lost.
     * @param active whether ping timeouts are active.
     */
    public void setPinger(boolean active) throws RemoteException {
      mEngine.setPinger(active);
    }
  
  };

}




Java Source Code List

org.lfx.azilink.AboutActivity.java
org.lfx.azilink.BootActivity.java
org.lfx.azilink.ForwardService.java
org.lfx.azilink.LinkStatistics.java
org.lfx.azilink.MainActivity.java
org.lfx.azilink.Reflection.java
org.lfx.azilink.net.IcmpKey.java
org.lfx.azilink.net.IcmpPacket.java
org.lfx.azilink.net.SelectThread.java
org.lfx.azilink.net.SocketHandler.java
org.lfx.azilink.net.TcpDriverCallback.java
org.lfx.azilink.net.TcpDriverImpl.java
org.lfx.azilink.net.TcpDriverPacketSink.java
org.lfx.azilink.net.TcpDriver.java
org.lfx.azilink.net.TcpEngine.java
org.lfx.azilink.net.TcpKey.java
org.lfx.azilink.net.TcpPacket.java
org.lfx.azilink.net.TcpToNio.java
org.lfx.azilink.net.TimerCallback.java
org.lfx.azilink.net.TimerQueue.java
org.lfx.azilink.net.TmAccept.java
org.lfx.azilink.net.TransferStatistics.java
org.lfx.azilink.net.UdpDriver.java
org.lfx.azilink.net.UdpEngine.java
org.lfx.azilink.net.UdpKey.java
org.lfx.azilink.net.UdpPacket.java
org.lfx.azilink.net.VpnLink.java
org.lfx.azilink.net.VpnNatEngineNotify.java
org.lfx.azilink.net.VpnNatEngine.java