1ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin/* 2ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Copyright (C) 2014 The Android Open Source Project 3ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 4ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * you may not use this file except in compliance with the License. 6ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * You may obtain a copy of the License at 7ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 8ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * http://www.apache.org/licenses/LICENSE-2.0 9ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 10ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Unless required by applicable law or agreed to in writing, software 11ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * distributed under the License is distributed on an "AS IS" BASIS, 12ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * See the License for the specific language governing permissions and 14ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * limitations under the License. 15ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 16ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 173830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberlingpackage com.android.camera.processing.imagebackend; 18ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 19ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberlingimport android.os.Process; 20ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling 21ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberlingimport com.android.camera.async.AndroidPriorityThread; 22ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport com.android.camera.debug.Log; 23abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Linimport com.android.camera.processing.ProcessingTaskConsumer; 24de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohdeimport com.android.camera.processing.memory.ByteBufferDirectPool; 25de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohdeimport com.android.camera.processing.memory.LruResourcePool; 2630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Linimport com.android.camera.session.CaptureSession; 2730ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Linimport com.android.camera.util.Size; 280f0329889f69182648fe8f535335e48978d63cc0I-Jong Linimport com.google.common.base.Optional; 290f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin 30de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohdeimport java.nio.ByteBuffer; 31ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.HashMap; 32ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.HashSet; 33ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.Map; 34ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.Set; 35ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.Executor; 36ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.ExecutorService; 37ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.Executors; 38ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.ThreadFactory; 39ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.locks.Condition; 40ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Linimport java.util.concurrent.locks.ReentrantLock; 41ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 42ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin/** 4330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * This ImageBackend is created for the purpose of creating a task-running 4430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * infrastructure that has two-level of priority and doing the book-keeping to 4530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * keep track of tasks that use Android Images. Android.media.images are 4630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * critical system resources that MUST be properly managed in order to maintain 4730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * camera application performance. Android.media.images are merely Java handles 4830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * to regions of physically contiguous memory used by the camera hardware as a 4930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * destination for imaging data. In general, this physically contiguous memory 5030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is not counted as an application resource, but as a system resources held by 5130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * the application and does NOT count against the limits of application memory. 5230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * The performance pressures of both computing and memory resources must often 5330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * be prioritized in releasing Android.media.images in a timely manner. In order 5430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * to properly balance these concerns, most image processing requested should be 5530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * routed through this object. This object is also responsible for releasing 5630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Android.media image as soon as possible, so as not to stall the camera 5730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * hardware subsystem. Image that reserve these images are a subclass of the 5830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * basic Java Runnable with a few conditions placed upon their run() 5930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * implementation: 60ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * <ol> 6130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * <li>The task will try to release the image as early as possible by calling 6230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * the releaseSemaphoreReference as soon as a reference to the original image is 6330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * no longer required.</li> 6430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * <li>A set of tasks that require ImageData must only happen on the first 6530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * receiveImage call. receiveImage must only be called once per image.</li> 6630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * <li>However, the submitted tasks may spawn new tasks via the appendTask with 6730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * any image that have had a task submitted, but NOT released via 6830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * releaseSemaphoreReference.</li> 6930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * <li>Computation that is dependent on multiple images should be written into 7030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * this task framework in a distributed manner where image task can be computed 7130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * independently and join their results to a common shared object.This style of 7230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * implementation allows for the earliest release of Android Images while 7330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * honoring the resources priorities set by this class. See the Lucky shot 7430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * implementation for a concrete example for this shared object and its 7530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * respective task {@link TaskLuckyShotSession} {@link LuckyShotSession}</li> 76ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * </ol> 77abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * To integrate with the ProcessingServiceManager, ImageBackend also signals to 78abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * the ProcessingServiceManager its processing state by enqueuing 790f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * ImageShadowTasks on each ImageBackend::receiveImage call. These ImageShadow 80abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * tasks have no implementation, but emulate the processing delay by blocking 81abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * until all tasks submitted and spawned by a particular receiveImage call have 82abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * completed their processing. This emulated functionality ensures that other 83abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * ProcessingTasks associated with Lens Blur and Panorama are not processing 84abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * while the ImageBackend is running. Unfairly, the ImageBackend proceeds with 85abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * its own processing regardless of the state of ImageShadowTask. 86abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * ImageShadowTasks that are associated with ImageBackend tasks that have 87abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * already been completed should return immediately on its process call. 88ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 893c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Linpublic class ImageBackend implements ImageConsumer, ImageTaskManager { 90ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling private static final Log.Tag TAG = new Log.Tag("ImageBackend"); 91ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 92ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected static final int NUM_THREADS_FAST = 2; 93e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin protected static final int NUM_THREADS_AVERAGE = 2; 94ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected static final int NUM_THREADS_SLOW = 2; 95ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 96ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling private static final int FAST_THREAD_PRIORITY = Process.THREAD_PRIORITY_DISPLAY; 97ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling private static final int AVERAGE_THREAD_PRIORITY = Process.THREAD_PRIORITY_DEFAULT 98ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling + Process.THREAD_PRIORITY_LESS_FAVORABLE; 99ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling private static final int SLOW_THREAD_PRIORITY = Process.THREAD_PRIORITY_BACKGROUND 100ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling + Process.THREAD_PRIORITY_MORE_FAVORABLE; 101ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling 102de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde private static final int IMAGE_BACKEND_HARD_REF_POOL_SIZE = 2; 103de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde 104abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protected final ProcessingTaskConsumer mProcessingTaskConsumer; 105abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 106abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 107abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Map for TaskImageContainer and the release of ImageProxy Book-keeping 108abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 1093830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling protected final Map<ImageToProcess, ImageReleaseProtocol> mImageSemaphoreMap; 110abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 111abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Map for ImageShadowTask and release of blocking on 112abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * ImageShadowTask::process 113abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 114abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protected final Map<CaptureSession, ImageShadowTask> mShadowTaskMap; 115ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 116e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin // The available threadpools for scheduling 117ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected final ExecutorService mThreadPoolFast; 118e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin protected final ExecutorService mThreadPoolAverage; 119ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected final ExecutorService mThreadPoolSlow; 120ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 121de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde private final LruResourcePool<Integer, ByteBuffer> mByteBufferDirectPool; 122ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 12330ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin /** 12430ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * Approximate viewable size (in pixels) for the fast thumbnail in the 12530ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * current UX definition of the product. Note that these values will be the 126abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * minimum size of FAST_THUMBNAIL target for the CONVERT_TO_RGB_PREVIEW 127abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * task. 12830ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin */ 1292c0832daaeca1bf9a0568ab1bfb7492303caaacfPaul Rohde private final Size mTinyThumbnailTargetSize; 13030ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin 13130ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin /** 13230ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * A standard viewable size (in pixels) for the filmstrip thumbnail in the 13330ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * current UX definition of the product. Note that this size is the minimum 13430ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin * size for the Preview on the filmstrip associated with 1354dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin * COMPRESS_TO_JPEG_AND_WRITE_TO_DISK task. 13630ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin */ 13730ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin private final static Size FILMSTRIP_THUMBNAIL_TARGET_SIZE = new Size(512, 384); 13830ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin 139ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Some invariants to know that we're keeping track of everything 140ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // that reflect the state of mImageSemaphoreMap 141ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private int mOutstandingImageRefs = 0; 142ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 143ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private int mOutstandingImageOpened = 0; 144ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 145ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private int mOutstandingImageClosed = 0; 146ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 147ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Objects that may be registered to this objects events. 148ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private ImageProcessorProxyListener mProxyListener = null; 149ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 150ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Default constructor, values are conservatively targeted to the Nexus 6 1512c0832daaeca1bf9a0568ab1bfb7492303caaacfPaul Rohde public ImageBackend(ProcessingTaskConsumer processingTaskConsumer, int tinyThumbnailSize) { 152ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolFast = Executors.newFixedThreadPool(NUM_THREADS_FAST, new FastThreadFactory()); 153e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin mThreadPoolAverage = Executors.newFixedThreadPool(NUM_THREADS_AVERAGE, 154e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin new AverageThreadFactory()); 155ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolSlow = Executors.newFixedThreadPool(NUM_THREADS_SLOW, new SlowThreadFactory()); 156de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde mByteBufferDirectPool = new ByteBufferDirectPool(IMAGE_BACKEND_HARD_REF_POOL_SIZE); 157ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mProxyListener = new ImageProcessorProxyListener(); 1583830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling mImageSemaphoreMap = new HashMap<>(); 159abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mShadowTaskMap = new HashMap<>(); 160abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mProcessingTaskConsumer = processingTaskConsumer; 1612c0832daaeca1bf9a0568ab1bfb7492303caaacfPaul Rohde mTinyThumbnailTargetSize = new Size(tinyThumbnailSize, tinyThumbnailSize); 162ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 163ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 164ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 165ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Direct Injection Constructor for Testing purposes. 166ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 167ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param fastService Service where Tasks of FAST Priority are placed. 168e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin * @param averageService Service where Tasks of AVERAGE Priority are placed. 169ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param slowService Service where Tasks of SLOW Priority are placed. 170ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param imageProcessorProxyListener iamge proxy listener to be used 171ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 172de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde public ImageBackend(ExecutorService fastService, 173de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde ExecutorService averageService, 174e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin ExecutorService slowService, 175de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde LruResourcePool<Integer, ByteBuffer> byteBufferDirectPool, 176abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin ImageProcessorProxyListener imageProcessorProxyListener, 177de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde ProcessingTaskConsumer processingTaskConsumer, 178de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde int tinyThumbnailSize) { 179ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolFast = fastService; 180e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin mThreadPoolAverage = averageService; 181ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolSlow = slowService; 182de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde mByteBufferDirectPool = byteBufferDirectPool; 183ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mProxyListener = imageProcessorProxyListener; 1843830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling mImageSemaphoreMap = new HashMap<>(); 185abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mShadowTaskMap = new HashMap<>(); 186abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mProcessingTaskConsumer = processingTaskConsumer; 1872c0832daaeca1bf9a0568ab1bfb7492303caaacfPaul Rohde mTinyThumbnailTargetSize = new Size(tinyThumbnailSize, tinyThumbnailSize); 188ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 189ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 190ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 1913c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * Simple getter for the associated listener object associated with this 19230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * instantiation that handles registration of events listeners. 193ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 194ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @return listener proxy that handles events messaging for this object. 195ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 196ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public ImageProcessorProxyListener getProxyListener() { 197ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return mProxyListener; 198ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 199ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 200abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 20130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Wrapper function for all log messages created by this object. Default 20230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * implementation is to send messages to the Android logger. For test 20330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * purposes, this method can be overridden to avoid "Stub!" Runtime 20430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * exceptions in Unit Tests. 205ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 206ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void logWrapper(String message) { 2070745f6eb1a8cbed85761e02839367ed8b2ff6ef6I-Jong Lin Log.v(TAG, message); 208ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 209ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 210ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 211ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @return Number of Image references currently held by this instance 212ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 213ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 214abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public int getNumberOfReservedOpenImages() { 215ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin synchronized (mImageSemaphoreMap) { 216ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // since mOutstandingImageOpened, mOutstandingImageClosed reflect 217ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // the historical state of mImageSemaphoreMap, we need to lock on 218ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // before we return a value. 219ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return mOutstandingImageOpened - mOutstandingImageClosed; 220ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 221ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 222ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 223ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 224abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Returns of the number of receiveImage calls that are currently enqueued 225abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * and/or being processed. 226abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 227abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @return The number of receiveImage calls that are currently enqueued 228abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * and/or being processed 229abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 230abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin @Override 231abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public int getNumberOfOutstandingCalls() { 232abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin synchronized (mShadowTaskMap) { 233abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin return mShadowTaskMap.size(); 234abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 235abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 236abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 237abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 23830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Signals the ImageBackend that a tasks has released a reference to the 23930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * image. Imagebackend determines whether all references have been released 24030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * and applies its specified release protocol of closing image and/or 24130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * unblocking the caller. Should ONLY be called by the tasks running on this 24230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * class. 243ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 244ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param img the image to be released by the task. 24530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param executor the executor on which the image close is run. if null, 24630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * image close is run by the calling thread (usually the main 24730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * task thread). 248ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 2493c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin @Override 2503830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public void releaseSemaphoreReference(final ImageToProcess img, Executor executor) { 251ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin synchronized (mImageSemaphoreMap) { 252ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin ImageReleaseProtocol protocol = mImageSemaphoreMap.get(img); 253ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (protocol == null || protocol.getCount() <= 0) { 254ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // That means task implementation has allowed an unbalanced 255ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // semaphore release. 256ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw new RuntimeException( 257ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin "ERROR: Task implementation did NOT balance its release."); 258ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 259ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 260ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Normal operation from here. 261ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protocol.addCount(-1); 262ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mOutstandingImageRefs--; 263ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin logWrapper("Ref release. Total refs = " + mOutstandingImageRefs); 264ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (protocol.getCount() == 0) { 265ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Image is ready to be released 266ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Remove the image from the map so that it may be submitted 267ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // again. 268ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mImageSemaphoreMap.remove(img); 269ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 270ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Conditionally close the image, specified by initial 271ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // receiveImage call 272ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (protocol.closeOnRelease) { 273ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin closeImageExecutorSafe(img, executor); 27430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin logWrapper("Ref release close."); 275ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 276ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 277ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Conditionally signal the blocking thread to go. 278ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (protocol.blockUntilRelease) { 279ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protocol.signal(); 280ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 281ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } else { 282ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Image is still being held by other tasks. 283ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Otherwise, update the semaphore 284ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mImageSemaphoreMap.put(img, protocol); 285ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 286ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 287ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 288ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 289ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 2903c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * Spawns dependent tasks from internal implementation of a set of tasks. If 2913c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * a dependent task does NOT require the image reference, it should be 2923c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * passed a null pointer as an image reference. In general, this method 2933c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * should be called after the task has completed its own computations, but 2943c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * before it has released its own image reference (via the 2953c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin * releaseSemaphoreReference call). 296ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 297ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param tasks The set of tasks to be run 298ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @return whether tasks are successfully submitted. 299ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 3003c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin @Override 3013830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public boolean appendTasks(ImageToProcess img, Set<TaskImageContainer> tasks) { 302ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Make sure that referred images are all the same, if it exists. 303ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // And count how image references need to be kept track of. 304ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin int countImageRefs = numPropagatedImageReferences(img, tasks); 305ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 306ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (img != null) { 307ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // If you're still holding onto the reference, make sure you keep 308ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // count 309ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin incrementSemaphoreReferenceCount(img, countImageRefs); 310ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 311ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 312abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Update the done count on the new tasks. 313abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin incrementTaskDone(tasks); 314abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 315ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin scheduleTasks(tasks); 316ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return true; 317ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 318ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 319ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 320ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Spawns a single dependent task from internal implementation of a task. 321ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 322ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param task The task to be run 323ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @return whether tasks are successfully submitted. 324ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 3253c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin @Override 3263830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public boolean appendTasks(ImageToProcess img, TaskImageContainer task) { 327ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin Set<TaskImageContainer> tasks = new HashSet<TaskImageContainer>(1); 328ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin tasks.add(task); 329ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return appendTasks(img, tasks); 330ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 331ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 332ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 33330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Implements that top-level image single task submission that is defined by 3340f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * the ImageConsumer interface w/o Runnable to executed. 335ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 336ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param img Image required by the task 337ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param task Task to be run 33830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param blockUntilImageRelease If true, call blocks until the object img 33930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is no longer referred by any task. If false, call is 34030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * non-blocking 34130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param closeOnImageRelease If true, images is closed when the object img 34230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is is no longer referred by any task. If false, After an image 34330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is submitted, it should never be submitted again to the 34430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * interface until all tasks and their spawned tasks are 345ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * finished. 3460f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @return whether jobs were enqueued to the ImageBackend. 347ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 348ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 3493830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public boolean receiveImage(ImageToProcess img, TaskImageContainer task, 3503c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin boolean blockUntilImageRelease, boolean closeOnImageRelease) 351ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throws InterruptedException { 3520f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin return receiveImage(img, task, blockUntilImageRelease, closeOnImageRelease, 3530f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin Optional.<Runnable> absent()); 3540f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } 3550f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin 3560f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin /** 3570f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * Implements that top-level image single task submission that is defined by 3580f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * the ImageConsumer interface. 3590f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * 3600f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @param img Image required by the task 3610f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @param task Task to be run 3620f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @param blockUntilImageRelease If true, call blocks until the object img 3630f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * is no longer referred by any task. If false, call is 3640f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * non-blocking 3650f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @param closeOnImageRelease If true, images is closed when the object img 3660f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * is is no longer referred by any task. If false, After an image 3670f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * is submitted, it should never be submitted again to the 3680f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * interface until all tasks and their spawned tasks are 3690f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * finished. 3700f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @param runnableWhenDone Optional runnable to be executed when the set of 3710f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * tasks are done. 3720f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @return whether jobs were enqueued to the ImageBackend. 3730f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin */ 3740f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin @Override 3750f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin public boolean receiveImage(ImageToProcess img, TaskImageContainer task, 3760f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin boolean blockUntilImageRelease, boolean closeOnImageRelease, 3770f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin Optional<Runnable> runnableWhenDone) 3780f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin throws InterruptedException { 379ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin Set<TaskImageContainer> passTasks = new HashSet<TaskImageContainer>(1); 380ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin passTasks.add(task); 3810f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin return receiveImage(img, passTasks, blockUntilImageRelease, closeOnImageRelease, 3820f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin runnableWhenDone); 3830f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } 3840f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin 3850f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin /** 3860f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * Returns an informational string about the current status of ImageBackend, 3870f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * along with an approximate number of references being held. 3880f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * 3890f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @return an informational string suitable to be dumped into logcat 3900f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin */ 3910f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin @Override 3920f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin public String toString() { 3930f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin return "ImageBackend Status BEGIN:\n" + 3940f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin "Shadow Image Map Size = " + mShadowTaskMap.size() + "\n" + 3950f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin "Image Semaphore Map Size = " + mImageSemaphoreMap.size() + "\n" + 3960f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin "OutstandingImageRefs = " + mOutstandingImageRefs + "\n" + 3970f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin "Proxy Listener Map Size = " + mProxyListener.getMapSize() + "\n" + 3980f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin "Proxy Listener = " + mProxyListener.getNumRegisteredListeners() + "\n" + 3990f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin "ImageBackend Status END:\n"; 400ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 401ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 402ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 40330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Implements that top-level image single task submission that is defined by 40430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * the ImageConsumer interface. 405ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 406ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param img Image required by the task 407ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param tasks A set of Tasks to be run 40830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param blockUntilImageRelease If true, call blocks until the object img 40930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is no longer referred by any task. If false, call is 41030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * non-blocking 41130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param closeOnImageRelease If true, images is closed when the object img 41230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is is no longer referred by any task. If false, After an image 41330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * is submitted, it should never be submitted again to the 41430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * interface until all tasks and their spawned tasks are 415ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * finished. 4160f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @param runnableWhenDone Optional runnable to be executed when the set of 4170f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * tasks are done. 4180f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @return whether receiveImage succeeded. Generally, only happens when the 4190f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * image reference is null or the task set is empty. 4200f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @throws InterruptedException occurs when call is set to be blocking and 4210f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * is interrupted. 422ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 423ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 4243830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public boolean receiveImage(ImageToProcess img, Set<TaskImageContainer> tasks, 4250f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin boolean blockUntilImageRelease, boolean closeOnImageRelease, 4260f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin Optional<Runnable> runnableWhenDone) 427ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throws InterruptedException { 428ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 429ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Short circuit if no tasks submitted. 430ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (tasks == null || tasks.size() <= 0) { 431ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return false; 432ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 433ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 434ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (img == null) { 435ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // TODO: Determine whether you need to be so strict at the top level 436ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw new RuntimeException("ERROR: Initial call must reference valid Image!"); 437ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 438ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 439ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Make sure that referred images are all the same, if it exists. 440ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // And count how image references need to be kept track of. 441ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin int countImageRefs = numPropagatedImageReferences(img, tasks); 442ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 443abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Initialize the counters for process-level tasks 4440f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin initializeTaskDone(tasks, runnableWhenDone); 445abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 446ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Set the semaphore, given that the number of tasks that need to be 447ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // scheduled 448ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // and the boolean flags for imaging closing and thread blocking 449ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin ImageReleaseProtocol protocol = setSemaphoreReferenceCount(img, countImageRefs, 450ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin blockUntilImageRelease, closeOnImageRelease); 451ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 452ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Put the tasks on their respective queues. 453ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin scheduleTasks(tasks); 454ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 455ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Implement blocking if required 456ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (protocol.blockUntilRelease) { 457ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protocol.block(); 458ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 459ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 460ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return true; 461ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 462ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 463ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 46430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Implements that top-level image task submission short-cut that is defined 46530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * by the ImageConsumer interface. 466ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 467ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param img Image required by the task 46830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param executor Executor to run events and image closes, in case of 46930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * control leakage 47030ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param processingFlags Magical bit vector that specifies jobs to be run 47130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * After an image is submitted, it should never be submitted 47230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * again to the interface until all tasks and their spawned tasks 47330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * are finished. 4740f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @param imageProcessorListener Optional listener to automatically register 4750f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * at the job task and unregister after all tasks are done 4760f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @return whether receiveImage succeeded. Generally, only happens when the 4770f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * image reference is null or the task set is empty. 4780f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @throws InterruptedException occurs when call is set to be blocking and 4790f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * is interrupted. 480ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 481ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 4823830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public boolean receiveImage(ImageToProcess img, Executor executor, 4830f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin Set<ImageTaskFlags> processingFlags, CaptureSession session, 4840f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin Optional<ImageProcessorListener> imageProcessorListener) 48530ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin throws InterruptedException { 486ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 4870f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin // Uncomment for occasional debugging 4880f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin // Log.v(TAG, toString()); 4890f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin 490ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin Set<TaskImageContainer> tasksToExecute = new HashSet<TaskImageContainer>(); 491ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 492ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (img == null) { 493ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // No data to process, just pure message. 494ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return true; 495ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 496ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 497ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Now add the pre-mixed versions of the tasks. 498ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 4994dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin if (processingFlags.contains(ImageTaskFlags.COMPRESS_TO_JPEG_AND_WRITE_TO_DISK)) { 5004dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin if (processingFlags.contains(ImageTaskFlags.CREATE_EARLY_FILMSTRIP_PREVIEW)) { 5014dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin // Request job that creates both filmstrip thumbnail from YUV, 502abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // JPEG compression of the YUV Image, and writes the result to 503abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // disk 5044dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin tasksToExecute.add(new TaskPreviewChainedJpeg(img, executor, this, session, 505de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde FILMSTRIP_THUMBNAIL_TARGET_SIZE, mByteBufferDirectPool)); 5064dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin } else { 507abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Request job that only does JPEG compression and writes the 508abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // result to disk 509de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde tasksToExecute.add(new TaskCompressImageToJpeg(img, executor, this, session, 510de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde mByteBufferDirectPool)); 5114dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin } 512ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 513ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 5144dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin if (processingFlags.contains(ImageTaskFlags.CONVERT_TO_RGB_PREVIEW)) { 5154dc301a073dab22b9bc12e0b846530d3a80bf8f7I-Jong Lin // Add an additional type of task to the appropriate queue. 51630ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin tasksToExecute.add(new TaskConvertImageToRGBPreview(img, executor, 51730ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin this, TaskImageContainer.ProcessingPriority.FAST, session, 5182c0832daaeca1bf9a0568ab1bfb7492303caaacfPaul Rohde mTinyThumbnailTargetSize, 51930ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin TaskConvertImageToRGBPreview.ThumbnailShape.SQUARE_ASPECT_CIRCULAR_INSET)); 520ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 521ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 5220f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin // Wrap the listener in a runnable that will be fired when all tasks are 5230f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin // complete. 5240f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin final Optional<Runnable> runnableOptional; 5250f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin if (imageProcessorListener.isPresent()) { 5260f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin final ImageProcessorListener finalImageProcessorListener = imageProcessorListener.get(); 5270f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin Runnable unregisterRunnable = new Runnable() { 5280f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin @Override 5290f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin public void run() { 5300f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin getProxyListener().unregisterListener(finalImageProcessorListener); 5310f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } 5320f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin }; 5330f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin runnableOptional = Optional.of(unregisterRunnable); 5340f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } else { 5350f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin runnableOptional = Optional.<Runnable> absent(); 5360f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } 537ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 5380f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin if (receiveImage(img, tasksToExecute, 5390f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin processingFlags.contains(ImageTaskFlags.BLOCK_UNTIL_ALL_TASKS_RELEASE), 5400f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin processingFlags.contains(ImageTaskFlags.CLOSE_ON_ALL_TASKS_RELEASE), 5410f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin runnableOptional)) { 5420f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin if (imageProcessorListener.isPresent()) { 5430f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin getProxyListener().registerListener(imageProcessorListener.get(), img.proxy); 5440f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } 5450f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin return true; 5460f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } else { 5470f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin return false; 5480f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } 549ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 550ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 551ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 552ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Factory functions, in case, you want some shake and bake functionality. 553ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 5543830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public TaskConvertImageToRGBPreview createTaskConvertImageToRGBPreview( 5553830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling ImageToProcess image, Executor executor, ImageBackend imageBackend, 55630ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin CaptureSession session, Size targetSize, 55730ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin TaskConvertImageToRGBPreview.ThumbnailShape thumbnailShape) { 55830ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin return new TaskConvertImageToRGBPreview(image, executor, imageBackend, 55930ef96534cc65c0ba4665f6da2fc36e879edf196I-Jong Lin TaskImageContainer.ProcessingPriority.FAST, session, 5602c0832daaeca1bf9a0568ab1bfb7492303caaacfPaul Rohde mTinyThumbnailTargetSize, thumbnailShape); 561ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 562ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 5633830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling public TaskCompressImageToJpeg createTaskCompressImageToJpeg(ImageToProcess image, 56430ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin Executor executor, ImageBackend imageBackend, CaptureSession session) { 565de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde return new TaskCompressImageToJpeg(image, executor, imageBackend, session, 566de2c5f84c216d91a366d3361be78a8c8710bd65dPaul Rohde mByteBufferDirectPool); 567ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 568ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 569ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 570ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Blocks and waits for all tasks to complete. 571ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 572ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 573ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void shutdown() { 574ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolSlow.shutdown(); 575ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mThreadPoolFast.shutdown(); 576ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 577ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 578ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 579abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * For a given set of starting tasks, initialize the associated sessions 580abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * with a proper blocking semaphore and value of number of tasks to be run. 581abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * For each semaphore, a ImageShadowTask will be instantiated and enqueued 582abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * onto the selected ProcessingSerivceManager. 583abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 584abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param tasks The set of ImageContainer tasks to be run on ImageBackend 585abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 5860f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin protected void initializeTaskDone(Set<TaskImageContainer> tasks, 5870f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin Optional<Runnable> runnableWhenDone) { 588abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin Set<CaptureSession> sessionSet = new HashSet<>(); 589abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin Map<CaptureSession, Integer> sessionTaskCount = new HashMap<>(); 590abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 591abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Create a set w/ no session duplicates and count them 592abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin for (TaskImageContainer task : tasks) { 593abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin sessionSet.add(task.mSession); 594abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin Integer currentCount = sessionTaskCount.get(task.mSession); 595abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin if (currentCount == null) { 596abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin sessionTaskCount.put(task.mSession, 1); 597abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } else { 598abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin sessionTaskCount.put(task.mSession, currentCount + 1); 599abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 600abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 601abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 602abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Create a new blocking semaphore for each set of tasks on a given 603abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // session. 604abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin synchronized (mShadowTaskMap) { 605abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin for (CaptureSession captureSession : sessionSet) { 606abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin BlockSignalProtocol protocol = new BlockSignalProtocol(); 607abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protocol.setCount(sessionTaskCount.get(captureSession)); 6080f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin final ImageShadowTask shadowTask; 6090f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin shadowTask = new ImageShadowTask(protocol, captureSession, 6100f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin runnableWhenDone); 611abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mShadowTaskMap.put(captureSession, shadowTask); 612abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mProcessingTaskConsumer.enqueueTask(shadowTask); 613abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 614abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 615abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 616abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 617abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 618abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * For ImageBackend tasks that spawn their own tasks, increase the semaphore 619abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * count to take into account the new tasks being spawned. 620abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 621abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param tasks The set of tasks to be spawned. 622abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 623abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protected void incrementTaskDone(Set<TaskImageContainer> tasks) throws RuntimeException { 624abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // TODO: Add invariant test so that all sessions are the same. 625abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin synchronized (mShadowTaskMap) { 626abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin for (TaskImageContainer task : tasks) { 627abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin ImageShadowTask shadowTask = mShadowTaskMap.get(task.mSession); 628abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin if (shadowTask == null) { 629abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin throw new RuntimeException( 630abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin "Session NOT previously registered." 631abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin + " ImageShadowTask booking-keeping is incorrect."); 632abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 633abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin shadowTask.getProtocol().addCount(1); 634abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 635abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 636abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 637abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 638abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 639abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Decrement the semaphore count of the ImageShadowTask. Should be called 640abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * when a task completes its processing in ImageBackend. 641abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 642abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param imageShadowTask The ImageShadow task that contains the blocking 643abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * semaphore. 6440f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @return whether all the tasks associated with an ImageShadowTask are done 645abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 6460f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin protected boolean decrementTaskDone(ImageShadowTask imageShadowTask) { 647abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin synchronized (mShadowTaskMap) { 648abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin int remainingTasks = imageShadowTask.getProtocol().addCount(-1); 649abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin if (remainingTasks == 0) { 650abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mShadowTaskMap.remove(imageShadowTask.getSession()); 651abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin imageShadowTask.getProtocol().signal(); 6520f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin return true; 6530f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } else { 6540f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin return false; 655abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 656abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 657abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 658abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 659abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 660abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 66130ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Puts the tasks on the specified queue. May be more complicated in the 66230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * future. 663ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 664ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param tasks The set of tasks to be run 665ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 666ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protected void scheduleTasks(Set<TaskImageContainer> tasks) { 667abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin synchronized (mShadowTaskMap) { 668abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin for (TaskImageContainer task : tasks) { 669abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin ImageShadowTask shadowTask = mShadowTaskMap.get(task.mSession); 670abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin if (shadowTask == null) { 671abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin throw new IllegalStateException("Scheduling a task with a unknown session."); 672abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 673abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Before scheduling, wrap TaskImageContainer inside of the 674abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // TaskDoneWrapper to add 675abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // instrumentation for managing ImageShadowTasks 676e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin switch (task.getProcessingPriority()) { 677e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin case FAST: 678e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin mThreadPoolFast.execute(new TaskDoneWrapper(this, shadowTask, task)); 679e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin break; 680e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin case AVERAGE: 681e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin mThreadPoolAverage.execute(new TaskDoneWrapper(this, shadowTask, task)); 682e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin break; 683e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin case SLOW: 684e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin mThreadPoolSlow.execute(new TaskDoneWrapper(this, shadowTask, task)); 685e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin break; 686e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin default: 687e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin mThreadPoolSlow.execute(new TaskDoneWrapper(this, shadowTask, task)); 688e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin break; 689abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 690ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 691ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 692ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 693ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 694ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 695ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * Initializes the semaphore count for the image 696ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 69730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @return The protocol object that keeps tracks of the image reference 69830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * count and actions to be taken on release. 699ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 7003830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling protected ImageReleaseProtocol setSemaphoreReferenceCount(ImageToProcess img, int count, 701ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin boolean blockUntilRelease, boolean closeOnRelease) throws RuntimeException { 702ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin synchronized (mImageSemaphoreMap) { 703ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (mImageSemaphoreMap.get(img) != null) { 704ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw new RuntimeException( 705abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin "ERROR: Rewriting of Semaphore Lock." 706abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin + " Image references may not freed properly"); 707ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 708ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 709ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Create the new booking-keeping object. 710ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin ImageReleaseProtocol protocol = new ImageReleaseProtocol(blockUntilRelease, 711ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin closeOnRelease); 712abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin protocol.setCount(count); 713ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 714ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mImageSemaphoreMap.put(img, protocol); 715ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mOutstandingImageRefs += count; 716ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mOutstandingImageOpened++; 717ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin logWrapper("Received an opened image: " + mOutstandingImageOpened + "/" 718ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin + mOutstandingImageClosed); 719ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin logWrapper("Setting an image reference count of " + count + " Total refs = " 720ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin + mOutstandingImageRefs); 721ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return protocol; 722ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 723ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 724ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 725ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 72630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Increments the semaphore count for the image. Should ONLY be internally 72730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * via appendTasks by internal tasks. Otherwise, image references could get 72830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * out of whack. 729abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * 730abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param img The Image associated with the set of tasks running on it. 731abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param count The number of tasks to be added 732abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @throws RuntimeException Indicates image Closing Bookkeeping is screwed 733abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * up. 734ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 7353830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling protected void incrementSemaphoreReferenceCount(ImageToProcess img, int count) 736ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throws RuntimeException { 737ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin synchronized (mImageSemaphoreMap) { 738ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin ImageReleaseProtocol protocol = mImageSemaphoreMap.get(img); 739ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (mImageSemaphoreMap.get(img) == null) { 740ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw new RuntimeException( 741ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin "Image Reference has already been released or has never been held."); 742ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 743ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 744ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin protocol.addCount(count); 745ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mImageSemaphoreMap.put(img, protocol); 746ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 747ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mOutstandingImageRefs += count; 748ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 749ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 750ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 751ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 75230ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Close an Image with a executor if it's available and does the proper 75330ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * booking keeping on the object. 754ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 755ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param img Image to be closed 75630ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * @param executor Executor to be used, if executor is null, the close is 75730ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * run on the task thread 758ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 7593830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling private void closeImageExecutorSafe(final ImageToProcess img, Executor executor) { 760ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin Runnable closeTask = new Runnable() { 761ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin @Override 762ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void run() { 7633830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling img.proxy.close(); 764ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mOutstandingImageClosed++; 765ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin logWrapper("Release of image occurred. Good fun. " + "Total Images Open/Closed = " 766ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin + mOutstandingImageOpened + "/" + mOutstandingImageClosed); 767ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 768ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin }; 769ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin if (executor == null) { 770ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Just run it on the main thread. 771ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin closeTask.run(); 772ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } else { 773ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin executor.execute(closeTask); 774ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 775ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 776ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 777ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 77830ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * Calculates the number of new Image references in a set of dependent 77930ccdac56450e5b1927e14a6eede2b86a30c42ebI-Jong Lin * tasks. Checks to make sure no new image references are being introduced. 780ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * 781ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin * @param tasks The set of dependent tasks to be run 782ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 7833830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling private int numPropagatedImageReferences(ImageToProcess img, Set<TaskImageContainer> tasks) 784ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throws RuntimeException { 785ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin int countImageRefs = 0; 786ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin for (TaskImageContainer task : tasks) { 7873830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling if (task.mImage != null && task.mImage != img) { 788ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw new RuntimeException("ERROR: Spawned tasks cannot reference new images!"); 789ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 790ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 7913830d419691ef865f01b362fee9618bac2aa8888Sascha Haeberling if (task.mImage != null) { 792ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin countImageRefs++; 793ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 794ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 795ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 796ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return countImageRefs; 797ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 798ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 799ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin /** 800abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Simple wrapper task to instrument when tasks ends so that ImageBackend 801abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * can fire events when set of tasks created by a ReceiveImage call have all 802abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * completed. 803ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin */ 804abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin private class TaskDoneWrapper implements Runnable { 805abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin private final ImageBackend mImageBackend; 806abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin private final ImageShadowTask mImageShadowTask; 8070f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin private final TaskImageContainer mWrappedTask; 808abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 809abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 810abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Constructor 8110f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * 812abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param imageBackend ImageBackend that the task is running on 813abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * @param imageShadowTask ImageShadowTask that is blocking on the 814abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * completion of the task 8150f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * @param wrappedTask The task to be run w/o instrumentation 816abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 817abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public TaskDoneWrapper(ImageBackend imageBackend, ImageShadowTask imageShadowTask, 8180f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin TaskImageContainer wrappedTask) { 819abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mImageBackend = imageBackend; 820abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mImageShadowTask = imageShadowTask; 8210f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin mWrappedTask = wrappedTask; 822abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 823ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 824abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 8250f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin * Adds instrumentation that runs when a TaskImageContainer completes. 826abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 827abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin @Override 828abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public void run() { 8290f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin mWrappedTask.run(); 830abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin // Decrement count 8310f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin if (mImageBackend.decrementTaskDone(mImageShadowTask)) { 8320f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin // If you're the last one... 8330f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin Runnable doneRunnable = mImageShadowTask.getRunnableWhenDone(); 8340f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin if (doneRunnable != null) { 8350f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin if (mWrappedTask.mExecutor == null) { 8360f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin doneRunnable.run(); 8370f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } else { 8380f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin mWrappedTask.mExecutor.execute(doneRunnable); 8390f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } 8400f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } 8410f0329889f69182648fe8f535335e48978d63cc0I-Jong Lin } 842abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 843abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 844ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 845abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 846abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * Encapsulates all synchronization for semaphore signaling and blocking. 847abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 848abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin static public class BlockSignalProtocol { 849ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private int count; 850ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 851ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private final ReentrantLock mLock = new ReentrantLock(); 852ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 853ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private Condition mSignal; 854ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 855ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void setCount(int value) { 856ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.lock(); 857ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin count = value; 858ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.unlock(); 859ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 860ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 861ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public int getCount() { 862ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin int value; 863ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.lock(); 864ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin value = count; 865ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.unlock(); 866ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return value; 867ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 868ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 869abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public int addCount(int value) { 870ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.lock(); 871abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin try { 872abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin count += value; 873abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin return count; 874abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } finally { 875abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin mLock.unlock(); 876abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 877ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 878ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 879abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin BlockSignalProtocol() { 880ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin count = 0; 881ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mSignal = mLock.newCondition(); 882ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 883ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 884ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void block() throws InterruptedException { 885ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.lock(); 886ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin try { 887ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin while (count != 0) { 888ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Spin to deal with spurious signals. 889ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mSignal.await(); 890ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 891ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } catch (InterruptedException e) { 892ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // TODO: on interruption, figure out what to do. 893ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin throw (e); 8943c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin } finally { 8953c7b7ec6aa2e51859718a6d6dead3c12d10ea370I-Jong Lin mLock.unlock(); 896ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 897ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 898ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 899ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public void signal() { 900ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.lock(); 901ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mSignal.signal(); 902ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin mLock.unlock(); 903ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 904ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 905ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 906ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 907abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin /** 908abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * A simple tuple class to keep track of image reference, and whether to 909abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * block and/or close on final image release. Instantiated on every task 910abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin * submission call. 911abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin */ 912abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin static public class ImageReleaseProtocol extends BlockSignalProtocol { 913abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 914abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public final boolean blockUntilRelease; 915abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 916abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin public final boolean closeOnRelease; 917abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 918abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin ImageReleaseProtocol(boolean block, boolean close) { 919abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin super(); 920abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin blockUntilRelease = block; 921abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin closeOnRelease = close; 922abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 923abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 924abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin } 925abac2a23443f13b58951d88bf4b972f31a562e3dI-Jong Lin 926ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin // Thread factories for a default constructor 927ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private class FastThreadFactory implements ThreadFactory { 928ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling @Override 929ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public Thread newThread(Runnable r) { 930ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling Thread t = new AndroidPriorityThread(FAST_THREAD_PRIORITY, r); 931ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return t; 932ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 933ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 934ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 935e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin private class AverageThreadFactory implements ThreadFactory { 936ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling @Override 937e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin public Thread newThread(Runnable r) { 938ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling Thread t = new AndroidPriorityThread(AVERAGE_THREAD_PRIORITY, r); 939e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin return t; 940e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin } 941e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin } 942e1bfecfb5efaa29419705b35706decece4985126I-Jong Lin 943ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin private class SlowThreadFactory implements ThreadFactory { 944ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling @Override 945ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin public Thread newThread(Runnable r) { 946ae474d0b2967b3995a4e1e334d6689b0cd9a38c9Sascha Haeberling Thread t = new AndroidPriorityThread(SLOW_THREAD_PRIORITY, r); 947ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin return t; 948ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 949ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin } 950ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin 951ed68932f91b4b4ad6766e4e38732deb8be772426I-Jong Lin} 952