aboutsummaryrefslogtreecommitdiff
path: root/apps/CameraITS/service/src/com/android/camera2/its/ItsService.java
diff options
context:
space:
mode:
Diffstat (limited to 'apps/CameraITS/service/src/com/android/camera2/its/ItsService.java')
-rw-r--r--apps/CameraITS/service/src/com/android/camera2/its/ItsService.java273
1 files changed, 164 insertions, 109 deletions
diff --git a/apps/CameraITS/service/src/com/android/camera2/its/ItsService.java b/apps/CameraITS/service/src/com/android/camera2/its/ItsService.java
index 7750464..d7e2525 100644
--- a/apps/CameraITS/service/src/com/android/camera2/its/ItsService.java
+++ b/apps/CameraITS/service/src/com/android/camera2/its/ItsService.java
@@ -92,6 +92,9 @@ public class ItsService extends Service implements SensorEventListener {
private static final long TIMEOUT_IDLE_MS = 2000;
private static final long TIMEOUT_STATE_MS = 500;
+ // Timeout to wait for a capture result after the capture buffer has arrived, in ms.
+ private static final long TIMEOUT_CAP_RES = 2000;
+
private static final int MAX_CONCURRENT_READER_BUFFERS = 8;
// Supports at most RAW+YUV+JPEG, one surface each.
@@ -129,13 +132,11 @@ public class ItsService extends Service implements SensorEventListener {
private volatile ServerSocket mSocket = null;
private volatile SocketRunnable mSocketRunnableObj = null;
- private volatile Thread mSocketThread = null;
private volatile BlockingQueue<ByteBuffer> mSocketWriteQueue =
new LinkedBlockingDeque<ByteBuffer>();
- private final Object mSocketWriteLock = new Object();
+ private final Object mSocketWriteEnqueueLock = new Object();
+ private final Object mSocketWriteDrainLock = new Object();
- private volatile SerializerRunnable mSerializerRunnableObj = null;
- private volatile Thread mSerializerThread = null;
private volatile BlockingQueue<Object[]> mSerializerQueue =
new LinkedBlockingDeque<Object[]>();
@@ -183,11 +184,9 @@ public class ItsService extends Service implements SensorEventListener {
@Override
public void onCreate() {
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
try {
+ mThreadExitFlag = false;
+
// Get handle to camera manager.
mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
if (mCameraManager == null) {
@@ -196,40 +195,6 @@ public class ItsService extends Service implements SensorEventListener {
mBlockingCameraManager = new BlockingCameraManager(mCameraManager);
mCameraListener = new BlockingStateCallback();
- // Open the camera device, and get its properties.
- String[] devices;
- try {
- devices = mCameraManager.getCameraIdList();
- if (devices == null || devices.length == 0) {
- throw new ItsException("No camera devices");
- }
- } catch (CameraAccessException e) {
- throw new ItsException("Failed to get device ID list", e);
- }
-
- // Args are a string, which is just the camera ID to open.
- int cameraId = 0;
- String args = intent.getDataString();
- if (args != null) {
- Logt.i(TAG, String.format("Received intent args: %s", args));
- cameraId = Integer.parseInt(args);
- }
- Logt.i(TAG, String.format("Opening camera %d", cameraId));
-
- mCameraThread = new HandlerThread("ItsCameraThread");
- try {
- mCameraThread.start();
- mCameraHandler = new Handler(mCameraThread.getLooper());
- mCamera = mBlockingCameraManager.openCamera(devices[cameraId],
- mCameraListener, mCameraHandler);
- mCameraCharacteristics = mCameraManager.getCameraCharacteristics(
- devices[cameraId]);
- } catch (CameraAccessException e) {
- throw new ItsException("Failed to open camera", e);
- } catch (BlockingOpenException e) {
- throw new ItsException("Failed to open camera (after blocking)", e);
- }
-
// Register for motion events.
mEvents = new LinkedList<MySensorEvent>();
mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
@@ -251,47 +216,101 @@ public class ItsService extends Service implements SensorEventListener {
}
// Create a thread to handle object serialization.
- mSerializerRunnableObj = new SerializerRunnable();
- mSerializerThread = new Thread(mSerializerRunnableObj);
- mSerializerThread.start();
+ (new Thread(new SerializerRunnable())).start();;
// Create a thread to receive capture results and process them.
mResultThread = new HandlerThread("ResultThread");
mResultThread.start();
mResultHandler = new Handler(mResultThread.getLooper());
+ // Create a thread for the camera device.
+ mCameraThread = new HandlerThread("ItsCameraThread");
+ mCameraThread.start();
+ mCameraHandler = new Handler(mCameraThread.getLooper());
+
// Create a thread to process commands, listening on a TCP socket.
mSocketRunnableObj = new SocketRunnable();
- mSocketThread = new Thread(mSocketRunnableObj);
- mSocketThread.start();
+ (new Thread(mSocketRunnableObj)).start();
} catch (ItsException e) {
Logt.e(TAG, "Service failed to start: ", e);
}
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ try {
+ // Just log a message indicating that the service is running and is able to accept
+ // socket connections.
+ while (!mThreadExitFlag && mSocket==null) {
+ Thread.sleep(1);
+ }
+ if (!mThreadExitFlag){
+ Logt.i(TAG, "ItsService ready");
+ } else {
+ Logt.e(TAG, "Starting ItsService in bad state");
+ }
+ } catch (java.lang.InterruptedException e) {
+ Logt.e(TAG, "Error starting ItsService (interrupted)", e);
+ }
return START_STICKY;
}
@Override
public void onDestroy() {
- try {
- mThreadExitFlag = true;
- for (int i = 0; i < MAX_NUM_OUTPUT_SURFACES; i++) {
- if (mSaveThreads[i] != null) {
- mSaveThreads[i].quit();
- mSaveThreads[i] = null;
- }
+ mThreadExitFlag = true;
+ for (int i = 0; i < MAX_NUM_OUTPUT_SURFACES; i++) {
+ if (mSaveThreads[i] != null) {
+ mSaveThreads[i].quit();
+ mSaveThreads[i] = null;
}
- if (mCameraThread != null) {
- mCameraThread.quitSafely();
- mCameraThread = null;
+ }
+ if (mResultThread != null) {
+ mResultThread.quitSafely();
+ mResultThread = null;
+ }
+ if (mCameraThread != null) {
+ mCameraThread.quitSafely();
+ mCameraThread = null;
+ }
+ }
+
+ public void openCameraDevice(int cameraId) throws ItsException {
+ Logt.i(TAG, String.format("Opening camera %d", cameraId));
+
+ String[] devices;
+ try {
+ devices = mCameraManager.getCameraIdList();
+ if (devices == null || devices.length == 0) {
+ throw new ItsException("No camera devices");
}
- try {
+ } catch (CameraAccessException e) {
+ throw new ItsException("Failed to get device ID list", e);
+ }
+
+ try {
+ mCamera = mBlockingCameraManager.openCamera(devices[cameraId],
+ mCameraListener, mCameraHandler);
+ mCameraCharacteristics = mCameraManager.getCameraCharacteristics(
+ devices[cameraId]);
+ } catch (CameraAccessException e) {
+ throw new ItsException("Failed to open camera", e);
+ } catch (BlockingOpenException e) {
+ throw new ItsException("Failed to open camera (after blocking)", e);
+ }
+ mSocketRunnableObj.sendResponse("cameraOpened", "");
+ }
+
+ public void closeCameraDevice() throws ItsException {
+ try {
+ if (mCamera != null) {
+ Logt.i(TAG, "Closing camera");
mCamera.close();
- } catch (Exception e) {
- throw new ItsException("Failed to close device");
+ mCamera = null;
}
- } catch (ItsException e) {
- Logt.e(TAG, "Script failed: ", e);
+ } catch (Exception e) {
+ throw new ItsException("Failed to close device");
}
+ mSocketRunnableObj.sendResponse("cameraClosed", "");
}
class SerializerRunnable implements Runnable {
@@ -299,7 +318,7 @@ public class ItsService extends Service implements SensorEventListener {
// the reflection).
public void run() {
Logt.i(TAG, "Serializer thread starting");
- while (true) {
+ while (! mThreadExitFlag) {
try {
Object objs[] = mSerializerQueue.take();
JSONObject jsonObj = new JSONObject();
@@ -358,20 +377,29 @@ public class ItsService extends Service implements SensorEventListener {
mOpenSocket = openSocket;
}
+ public void setOpenSocket(Socket openSocket) {
+ mOpenSocket = openSocket;
+ }
+
public void run() {
Logt.i(TAG, "Socket writer thread starting");
while (true) {
try {
ByteBuffer b = mSocketWriteQueue.take();
- if (b.hasArray()) {
- mOpenSocket.getOutputStream().write(b.array());
- } else {
- byte[] barray = new byte[b.capacity()];
- b.get(barray);
- mOpenSocket.getOutputStream().write(barray);
+ synchronized(mSocketWriteDrainLock) {
+ if (mOpenSocket == null) {
+ continue;
+ }
+ if (b.hasArray()) {
+ mOpenSocket.getOutputStream().write(b.array());
+ } else {
+ byte[] barray = new byte[b.capacity()];
+ b.get(barray);
+ mOpenSocket.getOutputStream().write(barray);
+ }
+ mOpenSocket.getOutputStream().flush();
+ Logt.i(TAG, String.format("Wrote to socket: %d bytes", b.capacity()));
}
- mOpenSocket.getOutputStream().flush();
- Logt.i(TAG, String.format("Wrote to socket: %d bytes", b.capacity()));
} catch (IOException e) {
Logt.e(TAG, "Error writing to socket", e);
break;
@@ -403,43 +431,69 @@ public class ItsService extends Service implements SensorEventListener {
} catch (IOException e) {
Logt.e(TAG, "Failed to create socket", e);
}
- try {
- Logt.i(TAG, "Waiting for client to connect to socket");
- mOpenSocket = mSocket.accept();
- if (mOpenSocket == null) {
- Logt.e(TAG, "Socket connection error");
- return;
- }
- Logt.i(TAG, "Socket connected");
- } catch (IOException e) {
- Logt.e(TAG, "Socket open error: ", e);
- return;
- }
- mSocketThread = new Thread(new SocketWriteRunnable(mOpenSocket));
- mSocketThread.start();
+
+ // Create a new thread to handle writes to this socket.
+ mSocketWriteRunnable = new SocketWriteRunnable(null);
+ (new Thread(mSocketWriteRunnable)).start();
+
while (!mThreadExitFlag) {
+ // Receive the socket-open request from the host.
try {
- BufferedReader input = new BufferedReader(
- new InputStreamReader(mOpenSocket.getInputStream()));
- if (input == null) {
- Logt.e(TAG, "Failed to get socket input stream");
- break;
- }
- String line = input.readLine();
- if (line == null) {
- Logt.e(TAG, "Failed to read socket line");
+ Logt.i(TAG, "Waiting for client to connect to socket");
+ mOpenSocket = mSocket.accept();
+ if (mOpenSocket == null) {
+ Logt.e(TAG, "Socket connection error");
break;
}
- processSocketCommand(line);
+ mSocketWriteQueue.clear();
+ mSocketWriteRunnable.setOpenSocket(mOpenSocket);
+ Logt.i(TAG, "Socket connected");
} catch (IOException e) {
- Logt.e(TAG, "Socket read error: ", e);
- break;
- } catch (ItsException e) {
- Logt.e(TAG, "Script error: ", e);
+ Logt.e(TAG, "Socket open error: ", e);
break;
}
+
+ // Process commands over the open socket.
+ while (!mThreadExitFlag) {
+ try {
+ BufferedReader input = new BufferedReader(
+ new InputStreamReader(mOpenSocket.getInputStream()));
+ if (input == null) {
+ Logt.e(TAG, "Failed to get socket input stream");
+ break;
+ }
+ String line = input.readLine();
+ if (line == null) {
+ Logt.i(TAG, "Socket readline retuned null (host disconnected)");
+ break;
+ }
+ processSocketCommand(line);
+ } catch (IOException e) {
+ Logt.e(TAG, "Socket read error: ", e);
+ break;
+ } catch (ItsException e) {
+ Logt.e(TAG, "Script error: ", e);
+ break;
+ }
+ }
+
+ // Close socket and go back to waiting for a new connection.
+ try {
+ synchronized(mSocketWriteDrainLock) {
+ mSocketWriteQueue.clear();
+ mOpenSocket.close();
+ mOpenSocket = null;
+ Logt.i(TAG, "Socket disconnected");
+ }
+ } catch (java.io.IOException e) {
+ Logt.e(TAG, "Exception closing socket");
+ }
}
+
+ // It's an overall error state if the code gets here; no recevery.
+ // Try to do some cleanup, but the service probably needs to be restarted.
Logt.i(TAG, "Socket server loop exited");
+ mThreadExitFlag = true;
try {
if (mOpenSocket != null) {
mOpenSocket.close();
@@ -456,7 +510,6 @@ public class ItsService extends Service implements SensorEventListener {
} catch (java.io.IOException e) {
Logt.w(TAG, "Exception closing socket");
}
- Logt.i(TAG, "Socket server thread exited");
}
public void processSocketCommand(String cmd)
@@ -464,7 +517,12 @@ public class ItsService extends Service implements SensorEventListener {
// Each command is a serialized JSON object.
try {
JSONObject cmdObj = new JSONObject(cmd);
- if ("getCameraProperties".equals(cmdObj.getString("cmdName"))) {
+ if ("open".equals(cmdObj.getString("cmdName"))) {
+ int cameraId = cmdObj.getInt("cameraId");
+ openCameraDevice(cameraId);
+ } else if ("close".equals(cmdObj.getString("cmdName"))) {
+ closeCameraDevice();
+ } else if ("getCameraProperties".equals(cmdObj.getString("cmdName"))) {
doGetProps();
} else if ("startSensorEvents".equals(cmdObj.getString("cmdName"))) {
doStartSensorEvents();
@@ -500,7 +558,7 @@ public class ItsService extends Service implements SensorEventListener {
}
ByteBuffer bstr = ByteBuffer.wrap(
(jsonObj.toString()+"\n").getBytes(Charset.defaultCharset()));
- synchronized(mSocketWriteLock) {
+ synchronized(mSocketWriteEnqueueLock) {
if (bstr != null) {
mSocketWriteQueue.put(bstr);
}
@@ -1039,8 +1097,10 @@ public class ItsService extends Service implements SensorEventListener {
ByteBuffer buf = ByteBuffer.wrap(img);
mSocketRunnableObj.sendResponseCaptureBuffer("rawImage", buf);
} else {
- // Wait until the corresponding capture result is ready.
- while (! mThreadExitFlag) {
+ // Wait until the corresponding capture result is ready, up to a timeout.
+ long t0 = android.os.SystemClock.elapsedRealtime();
+ while (! mThreadExitFlag
+ && android.os.SystemClock.elapsedRealtime()-t0 < TIMEOUT_CAP_RES) {
if (mCaptureResults[count] != null) {
Logt.i(TAG, "Writing capture as DNG");
DngCreator dngCreator = new DngCreator(
@@ -1062,13 +1122,10 @@ public class ItsService extends Service implements SensorEventListener {
mCountCallbacksRemaining.decrementAndGet();
} catch (IOException e) {
Logt.e(TAG, "Script error: ", e);
- mThreadExitFlag = true;
} catch (InterruptedException e) {
Logt.e(TAG, "Script error: ", e);
- mThreadExitFlag = true;
} catch (ItsException e) {
Logt.e(TAG, "Script error: ", e);
- mThreadExitFlag = true;
}
}
};
@@ -1198,10 +1255,8 @@ public class ItsService extends Service implements SensorEventListener {
}
} catch (ItsException e) {
Logt.e(TAG, "Script error: ", e);
- mThreadExitFlag = true;
} catch (Exception e) {
Logt.e(TAG, "Script error: ", e);
- mThreadExitFlag = true;
}
}