• 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.AsyncTask;
21 import android.os.Handler;
22 
23 import android.util.Log;
24 
25 import java.lang.InterruptedException;
26 import java.lang.Runnable;
27 import java.util.concurrent.CancellationException;
28 import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.TimeoutException;
30 import java.util.concurrent.TimeUnit;
31 
32 /**
33  * @hide
34  */
35 public class AsyncRunner extends GraphRunner{
36 
37     private Class mSchedulerClass;
38     private SyncRunner mRunner;
39     private AsyncRunnerTask mRunTask;
40 
41     private OnRunnerDoneListener mDoneListener;
42     private boolean isProcessing;
43 
44     private Exception mException;
45 
46     private class RunnerResult {
47         public int status = RESULT_UNKNOWN;
48         public Exception exception;
49     }
50 
51     private class AsyncRunnerTask extends AsyncTask<SyncRunner, Void, RunnerResult> {
52 
53         private static final String TAG = "AsyncRunnerTask";
54 
55         @Override
doInBackground(SyncRunner... runner)56         protected RunnerResult doInBackground(SyncRunner... runner) {
57             RunnerResult result = new RunnerResult();
58             try {
59                 if (runner.length > 1) {
60                     throw new RuntimeException("More than one runner received!");
61                 }
62 
63                 runner[0].assertReadyToStep();
64 
65                 // Preparation
66                 if (mLogVerbose) Log.v(TAG, "Starting background graph processing.");
67                 activateGlContext();
68 
69                 if (mLogVerbose) Log.v(TAG, "Preparing filter graph for processing.");
70                 runner[0].beginProcessing();
71 
72                 if (mLogVerbose) Log.v(TAG, "Running graph.");
73 
74                 // Run loop
75                 result.status = RESULT_RUNNING;
76                 while (!isCancelled() && result.status == RESULT_RUNNING) {
77                     if (!runner[0].performStep()) {
78                         result.status = runner[0].determinePostRunState();
79                         if (result.status == GraphRunner.RESULT_SLEEPING) {
80                             runner[0].waitUntilWake();
81                             result.status = RESULT_RUNNING;
82                         }
83                     }
84                 }
85 
86                 // Cleanup
87                 if (isCancelled()) {
88                     result.status = RESULT_STOPPED;
89                 }
90             } catch (Exception exception) {
91                 result.exception = exception;
92                 result.status = RESULT_ERROR;
93             }
94 
95             // Deactivate context.
96             try {
97                 deactivateGlContext();
98             } catch (Exception exception) {
99                 result.exception = exception;
100                 result.status = RESULT_ERROR;
101             }
102 
103             if (mLogVerbose) Log.v(TAG, "Done with background graph processing.");
104             return result;
105         }
106 
107         @Override
onCancelled(RunnerResult result)108         protected void onCancelled(RunnerResult result) {
109             onPostExecute(result);
110         }
111 
112         @Override
onPostExecute(RunnerResult result)113         protected void onPostExecute(RunnerResult result) {
114             if (mLogVerbose) Log.v(TAG, "Starting post-execute.");
115             setRunning(false);
116             if (result == null) {
117                 // Cancelled before got to doInBackground
118                 result = new RunnerResult();
119                 result.status = RESULT_STOPPED;
120             }
121             setException(result.exception);
122             if (result.status == RESULT_STOPPED || result.status == RESULT_ERROR) {
123                 if (mLogVerbose) Log.v(TAG, "Closing filters.");
124                 try {
125                     mRunner.close();
126                 } catch (Exception exception) {
127                     result.status = RESULT_ERROR;
128                     setException(exception);
129                 }
130             }
131             if (mDoneListener != null) {
132                 if (mLogVerbose) Log.v(TAG, "Calling graph done callback.");
133                 mDoneListener.onRunnerDone(result.status);
134             }
135             if (mLogVerbose) Log.v(TAG, "Completed post-execute.");
136         }
137     }
138 
139     private boolean mLogVerbose;
140     private static final String TAG = "AsyncRunner";
141 
142     /** Create a new asynchronous graph runner with the given filter
143      * context, and the given scheduler class.
144      *
145      * Must be created on the UI thread.
146      */
AsyncRunner(FilterContext context, Class schedulerClass)147     public AsyncRunner(FilterContext context, Class schedulerClass) {
148         super(context);
149 
150         mSchedulerClass = schedulerClass;
151         mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
152     }
153 
154     /** Create a new asynchronous graph runner with the given filter
155      * context. Uses a default scheduler.
156      *
157      * Must be created on the UI thread.
158      */
AsyncRunner(FilterContext context)159     public AsyncRunner(FilterContext context) {
160         super(context);
161 
162         mSchedulerClass = SimpleScheduler.class;
163         mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
164     }
165 
166     /** Set a callback to be called in the UI thread once the AsyncRunner
167      * completes running a graph, whether the completion is due to a stop() call
168      * or the filters running out of data to process.
169      */
170     @Override
setDoneCallback(OnRunnerDoneListener listener)171     public void setDoneCallback(OnRunnerDoneListener listener) {
172         mDoneListener = listener;
173     }
174 
175     /** Sets the graph to be run. Will call prepare() on graph. Cannot be called
176      * when a graph is already running.
177      */
setGraph(FilterGraph graph)178     synchronized public void setGraph(FilterGraph graph) {
179         if (isRunning()) {
180             throw new RuntimeException("Graph is already running!");
181         }
182         mRunner = new SyncRunner(mFilterContext, graph, mSchedulerClass);
183     }
184 
185     @Override
getGraph()186     public FilterGraph getGraph() {
187         return mRunner != null ? mRunner.getGraph() : null;
188     }
189 
190     /** Execute the graph in a background thread. */
191     @Override
run()192     synchronized public void run() {
193         if (mLogVerbose) Log.v(TAG, "Running graph.");
194         setException(null);
195 
196         if (isRunning()) {
197             throw new RuntimeException("Graph is already running!");
198         }
199         if (mRunner == null) {
200             throw new RuntimeException("Cannot run before a graph is set!");
201         }
202         mRunTask = this.new AsyncRunnerTask();
203 
204         setRunning(true);
205         mRunTask.execute(mRunner);
206     }
207 
208     /** Stop graph execution. This is an asynchronous call; register a callback
209      * with setDoneCallback to be notified of when the background processing has
210      * been completed. Calling stop will close the filter graph. */
211     @Override
stop()212     synchronized public void stop() {
213         if (mRunTask != null && !mRunTask.isCancelled() ) {
214             if (mLogVerbose) Log.v(TAG, "Stopping graph.");
215             mRunTask.cancel(false);
216         }
217     }
218 
219     @Override
close()220     synchronized public void close() {
221         if (isRunning()) {
222             throw new RuntimeException("Cannot close graph while it is running!");
223         }
224         if (mLogVerbose) Log.v(TAG, "Closing filters.");
225         mRunner.close();
226     }
227 
228     /** Check if background processing is happening */
229     @Override
isRunning()230     synchronized public boolean isRunning() {
231         return isProcessing;
232     }
233 
234     @Override
getError()235     synchronized public Exception getError() {
236         return mException;
237     }
238 
setRunning(boolean running)239     synchronized private void setRunning(boolean running) {
240         isProcessing = running;
241     }
242 
setException(Exception exception)243     synchronized private void setException(Exception exception) {
244         mException = exception;
245     }
246 
247 }
248