/* Copyright 2013 RobustNet Lab, University of Michigan. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mobilyzer; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.Callable; import android.content.Intent; import com.mobilyzer.MeasurementResult.TaskProgress; import com.mobilyzer.exceptions.MeasurementError; import com.mobilyzer.exceptions.MeasurementSkippedException; import com.mobilyzer.measurements.ParallelTask; import com.mobilyzer.measurements.SequentialTask; import com.mobilyzer.util.Logger; import com.mobilyzer.util.PhoneUtils; public class ServerMeasurementTask implements Callable<MeasurementResult[]> { private MeasurementTask realTask; private MeasurementScheduler scheduler; private ContextCollector contextCollector; private ResourceCapManager rManager; public ServerMeasurementTask(MeasurementTask task, MeasurementScheduler scheduler, ResourceCapManager manager) { realTask = task; this.scheduler = scheduler; this.contextCollector = new ContextCollector(); this.rManager = manager; } /** * Notify the scheduler that this task is started */ private void broadcastMeasurementStart() { Intent intent = new Intent(); intent.setAction(UpdateIntent.MEASUREMENT_PROGRESS_UPDATE_ACTION); intent.putExtra(UpdateIntent.TASK_STATUS_PAYLOAD, Config.TASK_STARTED); intent.putExtra(UpdateIntent.TASKID_PAYLOAD, realTask.getTaskId()); intent.putExtra(UpdateIntent.CLIENTKEY_PAYLOAD, realTask.getKey()); scheduler.sendBroadcast(intent); } /** * Notify the scheduler that this task is finished executing. The result can * be completed, paused or failed due to exception * * @param results * Results of the task * @param error * Measurement error leading to task's failure */ private void broadcastMeasurementEnd(MeasurementResult[] results, MeasurementError error) { // Only broadcast information about measurements if they are true // errors. if (!(error instanceof MeasurementSkippedException)) { Intent intent = new Intent(); intent.setAction(UpdateIntent.MEASUREMENT_PROGRESS_UPDATE_ACTION); intent.putExtra(UpdateIntent.TASK_STATUS_PAYLOAD, Config.TASK_FINISHED); intent.putExtra(UpdateIntent.TASK_PRIORITY_PAYLOAD, (int) realTask.getDescription().priority); intent.putExtra(UpdateIntent.TASKID_PAYLOAD, realTask.getTaskId()); intent.putExtra(UpdateIntent.CLIENTKEY_PAYLOAD, realTask.getKey()); intent.putExtra(UpdateIntent.TASK_TYPE_PAYLOAD, realTask.getType()); // if (realTask.getType().equals(SequentialTask.TYPE) || realTask.getType().equals(ParallelTask.TYPE)){ // intent.putExtra(UpdateIntent.TASK_DESC_PAYLOAD, realTask.getDescription()); // } if (results != null) { // Only single task can be paused if (results[0].getTaskProgress() == TaskProgress.PAUSED) { intent.putExtra(UpdateIntent.TASK_STATUS_PAYLOAD, Config.TASK_PAUSED); } else if (results[0].getTaskProgress() == TaskProgress.RESCHEDULED) { intent.putExtra(UpdateIntent.TASK_STATUS_PAYLOAD, Config.TASK_RESCHEDULED); intent.putExtra(UpdateIntent.RESULT_PAYLOAD, results); } else { intent.putExtra(UpdateIntent.TASK_STATUS_PAYLOAD, Config.TASK_FINISHED); intent.putExtra(UpdateIntent.RESULT_PAYLOAD, results); } scheduler.sendBroadcast(intent); } } } @Override public MeasurementResult[] call() throws MeasurementError { MeasurementResult[] results = null; PhoneUtils phoneUtils = PhoneUtils.getPhoneUtils(); try { phoneUtils.acquireWakeLock(); // if(!(phoneUtils.isCharging() || // phoneUtils.getCurrentBatteryLevel() > // rManager.getBatteryThresh())){ // throw new // MeasurementSkippedException("Not enough battery power"); // } if (!rManager.canScheduleExperiment()) { throw new MeasurementSkippedException( "Not enough battery power"); } if (PhoneUtils.getPhoneUtils().getNetwork() != PhoneUtils.NETWORK_WIFI) { try { if (rManager.isOverDataLimit(realTask.getMeasurementType())) { Logger.i("Skipping measurement - data limit is passed"); throw new MeasurementSkippedException("Over data limit"); } } catch (IOException e) { Logger.e("Exception occured during R/Wing of data stat file"); e.printStackTrace(); } } broadcastMeasurementStart(); try { contextCollector .setInterval(realTask.getDescription().contextIntervalSec); contextCollector.startCollector(); if (PhoneUtils.getPhoneUtils().getNetwork() != PhoneUtils.NETWORK_WIFI) { rManager.updateDataUsage(ResourceCapManager.PHONEUTILCOST); } results = realTask.call(); ArrayList<HashMap<String, String>> contextResults = contextCollector .stopCollector(); for (MeasurementResult r : results) { r.addContextResults(contextResults); r.getDeviceProperty().dnResolvability = contextCollector.dnsConnectivity; r.getDeviceProperty().ipConnectivity = contextCollector.ipConnectivity; } if (PhoneUtils.getPhoneUtils().getNetwork() != PhoneUtils.NETWORK_WIFI) { rManager.updateDataUsage(realTask.getDataConsumed()); } // if (realTask.getDescription().priority == MeasurementTask.GCM_PRIORITY) { // this.scheduler.checkin.uploadGCMMeasurementResult( // results[0], rManager); // } broadcastMeasurementEnd(results, null); } catch (MeasurementError e) { String error = "Server measurement " + realTask.getDescriptor() + " has failed: " + e.getMessage() + "\n"; Logger.e(error); results = MeasurementResult.getFailureResult(realTask, e); broadcastMeasurementEnd(results, e); } catch (Exception e) { String error = "Server measurement " + realTask.getDescriptor() + " has failed\n"; error += "Unexpected Exception: " + e.getMessage() + "\n"; Logger.e(error); results = MeasurementResult.getFailureResult(realTask, e); broadcastMeasurementEnd(results, new MeasurementError( "Got exception running task", e)); } } finally { phoneUtils.releaseWakeLock(); MeasurementTask currentTask = scheduler.getCurrentTask(); if (currentTask != null && currentTask.equals(realTask)) { scheduler.setCurrentTask(null); } } return results; } }