• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 package com.android.camera.one.v2.commands;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import android.hardware.camera2.CameraAccessException;
22 
23 import com.android.camera.async.SafeCloseable;
24 import com.android.camera.debug.Log;
25 import com.android.camera.debug.Logger;
26 import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionClosedException;
27 import com.android.camera.one.v2.core.ResourceAcquisitionFailedException;
28 import com.android.camera.util.Provider;
29 import com.google.common.util.concurrent.Futures;
30 
31 import java.util.concurrent.ExecutorService;
32 import java.util.concurrent.Future;
33 
34 import javax.annotation.Nullable;
35 import javax.annotation.concurrent.GuardedBy;
36 
37 /**
38  * Executes camera commands on a thread pool.
39  */
40 public class CameraCommandExecutor implements SafeCloseable {
41     private class CommandRunnable implements Runnable {
42         private final CameraCommand mCommand;
43 
CommandRunnable(CameraCommand command)44         public CommandRunnable(CameraCommand command) {
45             mCommand = command;
46         }
47 
48         @Override
run()49         public void run() {
50             try {
51                 mLog.d("Executing command: " + mCommand + " START");
52                 mCommand.run();
53                 mLog.d("Executing command: " + mCommand + " END");
54             } catch (ResourceAcquisitionFailedException e) {
55                 // This may indicate that the command would have otherwise
56                 // deadlocked waiting for resources which can never be acquired,
57                 // or the command was aborted because the necessary resources
58                 // will never be available because the system is shutting down.
59                 e.printStackTrace();
60             } catch (InterruptedException e) {
61                 // If interrupted, just return because the system is shutting
62                 // down.
63                 mLog.d("Interrupted while executing command: " + mCommand);
64             } catch (CameraAccessException e) {
65                 // If the camera was closed and the command failed, just return.
66                 mLog.d("Unable to connect to camera while executing command: " + mCommand);
67             } catch (CameraCaptureSessionClosedException e) {
68                 // If the session was closed and the command failed, just
69                 // return.
70                 mLog.d("Unable to connect to capture session while executing command: " +
71                         mCommand);
72             } catch (Exception e) {
73                 mLog.e("Exception when executing command: " + mCommand, e);
74             }
75         }
76     }
77 
78     private final Logger mLog;
79     private final Provider<ExecutorService> mExecutorProvider;
80     private final Object mLock;
81     @Nullable
82     @GuardedBy("mLock")
83     private ExecutorService mExecutor;
84     @GuardedBy("mLock")
85     private boolean mClosed;
86 
CameraCommandExecutor(Logger.Factory loggerFactory, Provider<ExecutorService> threadPoolExecutor)87     public CameraCommandExecutor(Logger.Factory loggerFactory,
88             Provider<ExecutorService> threadPoolExecutor) {
89         mLog = loggerFactory.create(new Log.Tag("CommandExecutor"));
90 
91         mLock = new Object();
92         mExecutorProvider = threadPoolExecutor;
93         mClosed = false;
94     }
95 
96     /**
97      * Executes the given command, returning a Future to indicate its status and
98      * allow (interruptible) cancellation.
99      */
execute(CameraCommand command)100     public Future<?> execute(CameraCommand command) {
101         if (mClosed) {
102             return Futures.immediateFuture(null);
103         }
104         synchronized (mLock) {
105             if (mExecutor == null) {
106                 // Create a new executor, if necessary.
107                 mExecutor = mExecutorProvider.get();
108             }
109             checkNotNull(mExecutor);
110             return mExecutor.submit(new CommandRunnable(command));
111         }
112     }
113 
114     /**
115      * Cancels any pending, or currently-executing commands.
116      * <p>
117      * Like {@link #close} but allows reusing the object.
118      */
flush()119     public void flush() {
120         synchronized (mLock) {
121             if (mExecutor != null) {
122                 mExecutor.shutdownNow();
123             }
124 
125             mExecutor = null;
126         }
127     }
128 
129     @Override
close()130     public void close() {
131         // Shutdown immediately by interrupting all currently-executing
132         // commands. Sending an interrupt is critical since commands may be
133         // waiting for results from the camera device which will never arrive,
134         // or for resources which may no longer be acquired.
135         synchronized (mLock) {
136             if (mExecutor != null) {
137                 mExecutor.shutdownNow();
138             }
139 
140             mExecutor = null;
141             mClosed = true;
142         }
143     }
144 }
145