• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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 
18 package android.filterfw.core;
19 
20 import android.os.ConditionVariable;
21 import android.util.Log;
22 
23 import java.lang.reflect.Constructor;
24 import java.lang.reflect.InvocationTargetException;
25 import java.util.concurrent.ScheduledThreadPoolExecutor;
26 import java.util.concurrent.TimeUnit;
27 
28 /**
29  * @hide
30  */
31 public class SyncRunner extends GraphRunner {
32 
33     private Scheduler mScheduler = null;
34 
35     private OnRunnerDoneListener mDoneListener = null;
36     private ScheduledThreadPoolExecutor mWakeExecutor = new ScheduledThreadPoolExecutor(1);
37     private ConditionVariable mWakeCondition = new ConditionVariable();
38 
39     private StopWatchMap mTimer = null;
40 
41     private final boolean mLogVerbose;
42     private final static String TAG = "SyncRunner";
43 
44     // TODO: Provide factory based constructor?
SyncRunner(FilterContext context, FilterGraph graph, Class schedulerClass)45     public SyncRunner(FilterContext context, FilterGraph graph, Class schedulerClass) {
46         super(context);
47 
48         mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
49 
50         if (mLogVerbose) Log.v(TAG, "Initializing SyncRunner");
51 
52         // Create the scheduler
53         if (Scheduler.class.isAssignableFrom(schedulerClass)) {
54             try {
55                 Constructor schedulerConstructor = schedulerClass.getConstructor(FilterGraph.class);
56                 mScheduler = (Scheduler)schedulerConstructor.newInstance(graph);
57             } catch (NoSuchMethodException e) {
58                 throw new RuntimeException("Scheduler does not have constructor <init>(FilterGraph)!", e);
59             } catch (InstantiationException e) {
60                 throw new RuntimeException("Could not instantiate the Scheduler instance!", e);
61             } catch (IllegalAccessException e) {
62                 throw new RuntimeException("Cannot access Scheduler constructor!", e);
63             } catch (InvocationTargetException e) {
64                 throw new RuntimeException("Scheduler constructor threw an exception", e);
65             } catch (Exception e) {
66                 throw new RuntimeException("Could not instantiate Scheduler", e);
67             }
68         } else {
69             throw new IllegalArgumentException("Class provided is not a Scheduler subclass!");
70         }
71 
72         // Associate this runner and the graph with the context
73         mFilterContext = context;
74         mFilterContext.addGraph(graph);
75 
76         mTimer = new StopWatchMap();
77 
78         if (mLogVerbose) Log.v(TAG, "Setting up filters");
79 
80         // Setup graph filters
81         graph.setupFilters();
82     }
83 
84     @Override
getGraph()85     public FilterGraph getGraph() {
86         return mScheduler != null ? mScheduler.getGraph() : null;
87     }
88 
step()89     public int step() {
90         assertReadyToStep();
91         if (!getGraph().isReady() ) {
92             throw new RuntimeException("Trying to process graph that is not open!");
93         }
94         return performStep() ? RESULT_RUNNING : determinePostRunState();
95     }
96 
beginProcessing()97     public void beginProcessing() {
98         mScheduler.reset();
99         getGraph().beginProcessing();
100     }
101 
close()102     public void close() {
103         // Close filters
104         if (mLogVerbose) Log.v(TAG, "Closing graph.");
105         getGraph().closeFilters(mFilterContext);
106         mScheduler.reset();
107     }
108 
109     @Override
run()110     public void run() {
111         if (mLogVerbose) Log.v(TAG, "Beginning run.");
112 
113         assertReadyToStep();
114 
115         // Preparation
116         beginProcessing();
117         boolean glActivated = activateGlContext();
118 
119         // Run
120         boolean keepRunning = true;
121         while (keepRunning) {
122             keepRunning = performStep();
123         }
124 
125         // Cleanup
126         if (glActivated) {
127             deactivateGlContext();
128         }
129 
130         // Call completion callback if set
131         if (mDoneListener != null) {
132             if (mLogVerbose) Log.v(TAG, "Calling completion listener.");
133             mDoneListener.onRunnerDone(determinePostRunState());
134         }
135         if (mLogVerbose) Log.v(TAG, "Run complete");
136     }
137 
138     @Override
isRunning()139     public boolean isRunning() {
140         return false;
141     }
142 
143     @Override
setDoneCallback(OnRunnerDoneListener listener)144     public void setDoneCallback(OnRunnerDoneListener listener) {
145         mDoneListener = listener;
146     }
147 
148     @Override
stop()149     public void stop() {
150         throw new RuntimeException("SyncRunner does not support stopping a graph!");
151     }
152 
153     @Override
getError()154     synchronized public Exception getError() {
155         return null;
156     }
157 
waitUntilWake()158     protected void waitUntilWake() {
159         mWakeCondition.block();
160     }
161 
processFilterNode(Filter filter)162     protected void processFilterNode(Filter filter) {
163         if (mLogVerbose) Log.v(TAG, "Processing filter node");
164         filter.performProcess(mFilterContext);
165         if (filter.getStatus() == Filter.STATUS_ERROR) {
166             throw new RuntimeException("There was an error executing " + filter + "!");
167         } else if (filter.getStatus() == Filter.STATUS_SLEEPING) {
168             if (mLogVerbose) Log.v(TAG, "Scheduling filter wakeup");
169             scheduleFilterWake(filter, filter.getSleepDelay());
170         }
171     }
172 
scheduleFilterWake(Filter filter, int delay)173     protected void scheduleFilterWake(Filter filter, int delay) {
174         // Close the wake condition
175         mWakeCondition.close();
176 
177         // Schedule the wake-up
178         final Filter filterToSchedule = filter;
179         final ConditionVariable conditionToWake = mWakeCondition;
180 
181         mWakeExecutor.schedule(new Runnable() {
182           @Override
183           public void run() {
184                 filterToSchedule.unsetStatus(Filter.STATUS_SLEEPING);
185                 conditionToWake.open();
186             }
187         }, delay, TimeUnit.MILLISECONDS);
188     }
189 
determinePostRunState()190     protected int determinePostRunState() {
191         boolean isBlocked = false;
192         for (Filter filter : mScheduler.getGraph().getFilters()) {
193             if (filter.isOpen()) {
194                 if (filter.getStatus() == Filter.STATUS_SLEEPING) {
195                     // If ANY node is sleeping, we return our state as sleeping
196                     return RESULT_SLEEPING;
197                 } else {
198                     // If a node is still open, it is blocked (by input or output)
199                     return RESULT_BLOCKED;
200                 }
201             }
202         }
203         return RESULT_FINISHED;
204     }
205 
206     // Core internal methods ///////////////////////////////////////////////////////////////////////
performStep()207     boolean performStep() {
208         if (mLogVerbose) Log.v(TAG, "Performing one step.");
209         Filter filter = mScheduler.scheduleNextNode();
210         if (filter != null) {
211             mTimer.start(filter.getName());
212             processFilterNode(filter);
213             mTimer.stop(filter.getName());
214             return true;
215         } else {
216             return false;
217         }
218     }
219 
assertReadyToStep()220     void assertReadyToStep() {
221         if (mScheduler == null) {
222             throw new RuntimeException("Attempting to run schedule with no scheduler in place!");
223         } else if (getGraph() == null) {
224             throw new RuntimeException("Calling step on scheduler with no graph in place!");
225         }
226     }
227 }
228