Back to project page dissertation-project.
The source code is released under:
MIT License
If you think the Android project dissertation-project listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.fyp.resilience.service; /*from w w w .j a v a 2 s . c om*/ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import android.app.Notification; import android.app.Service; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.net.wifi.p2p.WifiP2pInfo; import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener; import android.os.Handler; import android.os.IBinder; import android.preference.PreferenceManager; import android.util.Log; import com.fyp.resilience.Constants; import com.fyp.resilience.Flags; import com.fyp.resilience.PreferenceConstants; import com.fyp.resilience.R; import com.fyp.resilience.ResilienceApplication; import com.fyp.resilience.ResilienceController; import com.fyp.resilience.connection.Connectable; import com.fyp.resilience.connection.ServerUploadConnectable; import com.fyp.resilience.connection.WifiDownloadConnectable; import com.fyp.resilience.connection.WifiUploadConnectable; import com.fyp.resilience.database.model.DataPiece; import com.fyp.resilience.database.model.DataWhole; import com.fyp.resilience.event.ServerUploadFinished; import com.fyp.resilience.event.WifiDownloadFinished; import com.fyp.resilience.event.WifiUploadFinished; import com.fyp.resilience.receiver.AbstractConnectivityBroadcastReceiver; import com.fyp.resilience.receiver.ConnectivityBroadcastReceiver; import com.fyp.resilience.swarm.model.SwarmClient; import com.fyp.resilience.util.Utils; import com.fyp.resilience.widerst.Widerst; import de.greenrobot.event.EventBus; /** * Responsible for interpreting Event postings and deciding on the pieces that * must be uploaded. */ public class PieceUploadService extends Service implements ConnectionInfoListener, OnSharedPreferenceChangeListener { private static final String TAG = PieceUploadService.class.getSimpleName(); private static final int NOTIFICATION_ID = 100; private static final String VERIFICATION_STRING = "resilience_direct_client"; private ResilienceApplication mApplication; private ResilienceController mController; private Widerst mWiderstService; private ExecutorService mServerUploadExecutor; private ExecutorService mWifiUploadExecutor; private Notification.Builder mNotificationBuilder; private String mServerId; private static final int mMaximumServerConnections = 1; private int mMaximumWifiConnections; private int mCurrentServerConnections; private int mCurrentWifiConnections; private ServerSocket mSocket; private Thread mAcceptThread; private Thread mDirectRegistrationThread; private IntentFilter mConnIntentFilter; private AbstractConnectivityBroadcastReceiver mConnBroadcastReceiver; private long mCurrentBackOff = 0; private static final Handler mainHandler = new Handler(); private final Runnable mWifiConnRunnable = new Runnable() { @Override public void run() { mCurrentWifiConnections++; updateNotification(); } }; /** * Responsible for listening to {@link Socket} connections sent from * {@link WifiUploadConnectable}s. */ class ClientSocketHandler implements Runnable { @Override public void run() { while (!Thread.interrupted()) { try { Socket clientSocket = mSocket.accept(); Log.d(TAG, "Client has hit service!"); Connectable wifiConnection = new WifiDownloadConnectable( PieceUploadService.this, null, clientSocket); final InetAddress clientAddress = clientSocket.getInetAddress(); mainHandler.post(new Runnable() { @Override public void run() { SwarmClient client = mController.getClientFromListWithAddress(clientAddress); if (null == client) { mController.addClientToList(new SwarmClient(clientAddress, Constants.CLIENT_DATA_PORT)); } } }); mWifiUploadExecutor.submit(wifiConnection); mController.addConnection(wifiConnection); mainHandler.post(mWifiConnRunnable); } catch (Exception e) { e.printStackTrace(); } } } } /** * {@link Runnable} that is posted to the UI Thread. */ class DirectAddToSwarmRunnable implements Runnable { private final InetAddress mAddress; public DirectAddToSwarmRunnable(final InetAddress address) { mAddress = address; } @Override public void run() { mController.addClientToList(new SwarmClient(mAddress, Constants.CLIENT_DATA_PORT)); getAndPostNextWifiUploads(); } } /** * Responsible for listening to {@link Socket} connections send from Wi-Fi * Direct Peers. */ class WifiDirectClientVerification implements Runnable { @Override public void run() { try { final ServerSocket registerSocket = new ServerSocket(Constants.CLIENT_VERIFICATION_PORT); while (!Thread.interrupted()) { Socket newConnection = registerSocket.accept(); Log.d(TAG, "Wi-Fi Direct client is registering"); final ObjectInputStream input = new ObjectInputStream(newConnection.getInputStream()); final Object verificationObject = input.readObject(); /* Ensure it is of type String */ if (verificationObject.getClass().equals(String.class)) { final String testString = (String) verificationObject; if (testString.equals(VERIFICATION_STRING)) { Log.d(TAG, "Registered a client: " + newConnection.getInetAddress()); mainHandler.post(new DirectAddToSwarmRunnable(newConnection.getInetAddress())); } } input.close(); newConnection.close(); } } catch (Exception e) { e.printStackTrace(); } } } /** * Responsible for posting peer verification connections to the Wi-Fi Direct * Group Owner. */ static class WifiDirectClientRegistration implements Runnable { private final InetAddress mGroupOwnerAddress; private static final int retries = 3; public WifiDirectClientRegistration(final InetAddress groupOwner) { mGroupOwnerAddress = groupOwner; } @Override public void run() { int count = 0; while (count <= retries) { try { /* Ensure the connection has settled */ Thread.sleep(2000); final Socket newConnection = new Socket(mGroupOwnerAddress, Constants.CLIENT_VERIFICATION_PORT); Log.d(TAG, "Registering with Group Owner: " + mGroupOwnerAddress); final ObjectOutputStream output = new ObjectOutputStream(newConnection.getOutputStream()); output.writeObject(new String(VERIFICATION_STRING)); output.flush(); output.close(); newConnection.close(); break; } catch (Exception e) { e.printStackTrace(); count++; } } } } @Override public int onStartCommand(final Intent intent, final int flags, final int startId) { /* * If connected to a Wi-Fi connection then start the Network Service * Discovery helper */ if (mController.getSwarmList().size() > 0) { if (mController.hasFilesWaiting()) { getAndPostNextWifiUploads(); } } /* * If the device currently has a connection to the Internet, then * attempt a post to the server */ if (ConnectivityBroadcastReceiver.isConnected(this)) { getAndPostNextServerUploads(); } return START_STICKY; } @Override public void onCreate() { super.onCreate(); if (Flags.DEBUG) { Log.i(TAG, "onCreate has been called"); } /* Register this object with the EventBus */ EventBus.getDefault().register(this); /* Obtain Application instances */ mApplication = ResilienceApplication.getApplication(this); mController = mApplication.getResilienceController(); mServerUploadExecutor = mApplication.getServerUploadThreadExecutorService(); mWifiUploadExecutor = mApplication.getWifiUploadThreadExecutorService(); mMaximumWifiConnections = mApplication.getMaximumWifiThreads(); mWiderstService = mApplication.getWiderstService(); /* Retrieve initial preference settings */ final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); sharedPreferences.registerOnSharedPreferenceChangeListener(this); mServerId = sharedPreferences.getString(PreferenceConstants.SERVER_ID_KEY, ""); /* Initialise ConnectivityBroadcastReceiver */ mConnIntentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); mConnIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); mConnBroadcastReceiver = new ConnectivityBroadcastReceiver(mController, (WifiManager) getSystemService(WIFI_SERVICE), this); registerReceiver(mConnBroadcastReceiver, mConnIntentFilter); try { mSocket = new ServerSocket(Constants.CLIENT_DATA_PORT); if (null != mSocket) { mAcceptThread = new Thread(new ClientSocketHandler(), "Wi-Fi Acceptance"); mAcceptThread.start(); mDirectRegistrationThread = new Thread(new WifiDirectClientVerification(), "Wi-Fi Direct Registration"); mDirectRegistrationThread.start(); } } catch (IOException e) { e.printStackTrace(); } } @Override public void onDestroy() { stopForeground(true); mConnBroadcastReceiver.onDestroy(); EventBus.getDefault().unregister(this); PreferenceManager.getDefaultSharedPreferences(this) .unregisterOnSharedPreferenceChangeListener(this); if (Flags.DEBUG) { Log.i(TAG, "onDestroy has been called"); } mController.clearClientList(); mAcceptThread.interrupt(); mDirectRegistrationThread.interrupt(); unregisterReceiver(mConnBroadcastReceiver); super.onDestroy(); } @Override public IBinder onBind(final Intent intent) { return null; } /** * Attempts to retrieve and upload waiting {@link DataPiece}s to the Widerst * server. */ private void getAndPostNextServerUploads() { if (!Utils.canUploadToServer(this) || mCurrentServerConnections >= mMaximumServerConnections) { return; } final DataPiece dataPiece = mController.getNextDataPieceToUpload(); if (null == dataPiece) { if (mController.getConnectionList().size() == 0) { stopForeground(true); } return; } Connectable connectable = null; final DataWhole dataWhole = dataPiece.getParent(); try { File uploadFile = null; if (dataWhole.isOwned()) { uploadFile = dataWhole.getFile(this); } else { uploadFile = dataPiece.getFile(this); } if (null == uploadFile) { Log.e(TAG, "FOUND A NULL FILE!?"); return; } connectable = new ServerUploadConnectable(this, dataWhole, dataPiece, uploadFile, mWiderstService, mServerId, mCurrentBackOff); } catch (FileNotFoundException fe) { if (!dataWhole.getFile(this).exists()) { // TODO: what to do if file has been deleted } } catch (Exception e) { e.printStackTrace(); } if (null != connectable) { mController.addConnection(connectable); mServerUploadExecutor.submit(connectable); mCurrentServerConnections++; updateNotification(); } } /** * Attempts to retrieve and upload waiting {@link DataPiece}s to * {@link SwarmClient}s. */ private void getAndPostNextWifiUploads() { /* Obtain all pieces that require an upload */ final List<DataPiece> uploadPieces = mController.getAllPiecesToUpload(); if (uploadPieces.size() == 0) { if (mController.getConnectionList().size() == 0) { stopForeground(true); } return; } for (final DataPiece piece : uploadPieces) { /* * Wi-Fi connections can be triggered by incoming connections. * Therefore, it is impossible to control the amount that come in * but is possible to limit those going out. */ if (mCurrentWifiConnections >= mMaximumWifiConnections) { return; } List<SwarmClient> swarmList = mController.getSwarmList(); if (swarmList.size() == 0) { return; } SwarmClient swarmClient = null; for (final SwarmClient client : swarmList) { if (!client.isBusy() && !client.hasPiece(piece)) { swarmClient = client; break; } } if (swarmClient != null) { final DataWhole dataWhole = piece.getParent(); File uploadFile = null; /* If a DataWhole is owned then it WILL have a file attached */ if (dataWhole.isOwned()) { uploadFile = dataWhole.getFile(this); } else { uploadFile = piece.getFile(this); } if (null != uploadFile) { Connectable connectable = null; try { connectable = new WifiUploadConnectable(this, dataWhole, piece, uploadFile, swarmClient); } catch (FileNotFoundException fe) { // TODO } catch (Exception e) { // TODO } if (null != connectable) { swarmClient.setBusy(true); mController.addConnection(connectable); mWifiUploadExecutor.submit(connectable); mCurrentWifiConnections++; updateNotification(); } } } } } /** * @param The {@link ServerUploadFinished} event posted to the EventBus. */ public void onEventMainThread(final ServerUploadFinished event) { mCurrentServerConnections--; int status = event.getConnectable().getConnectionStatus(); if (status == Connectable.STATUS_CONNECTION_ERROR || status == Connectable.STATUS_RETRYABLE) { /* Calculate the backoff on failure */ calculateBackoff(); } else { /* Reset any backoff value */ mCurrentBackOff = 0; } getAndPostNextServerUploads(); getAndPostNextWifiUploads(); } /** * @param The {@link WifiUploadFinished} event posted to the EventBus. */ public void onEventMainThread(final WifiUploadFinished event) { Log.d(TAG, "A Wi-Fi upload has finished!"); final SwarmClient swarmClient = mController.getClientFromListWithAddress(event.getConnectable().getClient() .getAddress()); if (null != swarmClient) { swarmClient.setBusy(false); if (event.getConnectable().getConnectionStatus() == Connectable.STATUS_SUCCESS) { swarmClient.addSuccessfulAttempt(); swarmClient.addPieceToMap(event.getConnectable().getDataPiece()); } else { if (swarmClient.getFailedAttempts() >= Constants.MAX_SWARM_CLIENT_RETRIES) { /* Remove the client if it */ mController.removeClientFromList(swarmClient); } else { swarmClient.addFailedAttempt(); } } } mCurrentWifiConnections--; updateNotification(); getAndPostNextWifiUploads(); } /** * @param The {@link WifiDownloadFinished} event posted to the EventBus. */ public void onEventMainThread(final WifiDownloadFinished event) { if (event.getConnectable().getConnectionStatus() == Connectable.STATUS_SUCCESS) { final SwarmClient client = mController.getClientFromListWithAddress(event.getConnectable().getSocket() .getInetAddress()); if (null != client) { final DataPiece piece = event.getConnectable().getPiece(); /* * Add the piece to the client map so that we don't attempt to * upload to the same client */ if (null != piece) { client.addPieceToMap(piece); } } } mCurrentWifiConnections--; updateNotification(); getAndPostNextServerUploads(); getAndPostNextWifiUploads(); } /** * Calculates the exponential back-off for a Server connection. If a * connection fails then the current back-off is doubled. */ private void calculateBackoff() { if (mCurrentBackOff > 0) { if ((mCurrentBackOff << 1) < Constants.MAXIMUM_BACKOFF) { mCurrentBackOff <<= 1; return; } } mCurrentBackOff = TimeUnit.SECONDS.toMillis(2); } /** * Create/Update the foreground notification. */ private void updateNotification() { /* Create the Notification if it doesn't already exist */ if (null == mNotificationBuilder) { mNotificationBuilder = new Notification.Builder(this) .setOngoing(true) .setContentTitle("Resilience") .setSmallIcon(R.drawable.ic_launcher); } /* Set Notification information */ mNotificationBuilder.setContentText("Server Connections: " + mCurrentServerConnections + "\n" + "Wi-Fi Connections: " + mCurrentWifiConnections); startForeground(NOTIFICATION_ID, mNotificationBuilder.build()); } @Override public void onConnectionInfoAvailable(final WifiP2pInfo info) { /* * Perform check to see who is group owner. This will determine which * device goes first. */ if (info.isGroupOwner) { Log.d(TAG, "Connected as group owner"); } else { new Thread(new WifiDirectClientRegistration(info.groupOwnerAddress)).start(); mController.addClientToList(new SwarmClient(info.groupOwnerAddress, Constants.CLIENT_DATA_PORT)); getAndPostNextWifiUploads(); Log.d(TAG, "Connected as peer"); } } @Override public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { if (key.equals(PreferenceConstants.SERVER_ID_KEY)) { mServerId = sharedPreferences.getString(PreferenceConstants.SERVER_ID_KEY, ""); } getAndPostNextServerUploads(); } }