/* * 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.measurements; import java.io.InvalidClassException; import java.security.InvalidParameterException; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import android.os.Parcel; import android.os.Parcelable; import com.mobilyzer.Config; import com.mobilyzer.MeasurementDesc; import com.mobilyzer.MeasurementResult; import com.mobilyzer.MeasurementTask; import com.mobilyzer.exceptions.MeasurementError; import com.mobilyzer.util.Logger; /** * * @author Ashkan Nikravesh (ashnik@umich.edu) * * Parallel Task is a measurement task that can execute more than one measurement task * in parallel using a thread pool. */ public class ParallelTask extends MeasurementTask{ private long duration; private List<MeasurementTask> tasks; private ExecutorService executor; // Type name for internal use public static final String TYPE = "parallel"; // Human readable name for the task public static final String DESCRIPTOR = "parallel"; private long dataConsumed; public static class ParallelDesc extends MeasurementDesc { public ParallelDesc(String key, Date startTime, Date endTime, double intervalSec, long count, long priority, int contextIntervalSec, Map<String, String> params) throws InvalidParameterException { super(ParallelTask.TYPE, key, startTime, endTime, intervalSec, count, priority, contextIntervalSec, params); // initializeParams(params); } @Override protected void initializeParams(Map<String, String> params) { } @Override public String getType() { return ParallelTask.TYPE; } protected ParallelDesc(Parcel in) { super(in); } public static final Parcelable.Creator<ParallelDesc> CREATOR = new Parcelable.Creator<ParallelDesc>() { public ParallelDesc createFromParcel(Parcel in) { return new ParallelDesc(in); } public ParallelDesc[] newArray(int size) { return new ParallelDesc[size]; } }; } @SuppressWarnings("rawtypes") public static Class getDescClass() throws InvalidClassException { return ParallelDesc.class; } public ParallelTask(MeasurementDesc desc, ArrayList<MeasurementTask> tasks) { super(new ParallelDesc(desc.key, desc.startTime, desc.endTime, desc.intervalSec, desc.count, desc.priority, desc.contextIntervalSec, desc.parameters)); this.tasks=(List<MeasurementTask>) tasks.clone(); long maxduration=0; for(MeasurementTask mt: tasks){ if(mt.getDuration()>maxduration){ maxduration=mt.getDuration(); } } this.duration=maxduration; this.dataConsumed=0; } protected ParallelTask(Parcel in) { super(in); // ClassLoader loader = Thread.currentThread().getContextClassLoader(); // we cannot directly cast Parcelable[] to MeasurementTask[]. Cast them one-by-one Parcelable[] tempTasks = in.readParcelableArray(MeasurementTask.class.getClassLoader()); tasks = new ArrayList<MeasurementTask>(); long maxDuration = 0; for ( Parcelable pTask : tempTasks ) { MeasurementTask mt = (MeasurementTask) pTask; tasks.add(mt); if (mt.getDuration() > maxDuration) { maxDuration = mt.getDuration(); } } this.duration = maxDuration; this. dataConsumed = 0; } public static final Parcelable.Creator<ParallelTask> CREATOR = new Parcelable.Creator<ParallelTask>() { public ParallelTask createFromParcel(Parcel in) { return new ParallelTask(in); } public ParallelTask[] newArray(int size) { return new ParallelTask[size]; } }; @Override public int describeContents() { return super.describeContents(); } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeParcelableArray(tasks.toArray(new MeasurementTask[tasks.size()]), flags); } @Override public String getDescriptor() { return DESCRIPTOR; } @Override public MeasurementResult[] call() throws MeasurementError { long timeout=duration; executor=Executors.newFixedThreadPool(this.tasks.size()); if(timeout==0){ timeout=Config.DEFAULT_PARALLEL_TASK_DURATION; }else{ //this is the longest time a task can run before it is forcibly killed timeout*=2; } ArrayList<MeasurementResult> allResults=new ArrayList<MeasurementResult>(); List<Future<MeasurementResult[]>> futures; try { futures=executor.invokeAll(this.tasks,timeout,TimeUnit.MILLISECONDS); for(Future<MeasurementResult[]> f: futures){ MeasurementResult[] r=f.get(); for(int i=0;i<r.length;i++){ allResults.add(r[i]); } } } catch (InterruptedException e) { Logger.e("Parallel task " + this.getTaskId()+" got interrupted"); }catch (ExecutionException e) { throw new MeasurementError("Execution error: " + e.getCause()); } finally{ executor.shutdown(); } return (MeasurementResult[])allResults.toArray( new MeasurementResult[allResults.size()]); } @Override public String getType() { return ParallelTask.TYPE; } @Override public MeasurementTask clone() { MeasurementDesc desc = this.measurementDesc; ParallelDesc newDesc = new ParallelDesc(desc.key, desc.startTime, desc.endTime, desc.intervalSec, desc.count, desc.priority, desc.contextIntervalSec, desc.parameters); ArrayList<MeasurementTask> newTaskList=new ArrayList<MeasurementTask>(); for(MeasurementTask mt: tasks){ newTaskList.add(mt.clone()); } return new ParallelTask(newDesc,newTaskList); } @Override public boolean stop() { return false; } @Override public long getDuration() { return duration; } @Override public void setDuration(long newDuration) { if(newDuration<0){ this.duration=0; }else{ this.duration=newDuration; } } public MeasurementTask[] getTasks() { return tasks.toArray(new MeasurementTask[tasks.size()]); } //TODO @Override public long getDataConsumed() { return dataConsumed; } }