1525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov/* 2525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * Copyright (C) 2014 The Android Open Source Project 3525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * 4525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 5525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * you may not use this file except in compliance with the License. 6525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * You may obtain a copy of the License at 7525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * 8525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * http://www.apache.org/licenses/LICENSE-2.0 9525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * 10525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * Unless required by applicable law or agreed to in writing, software 11525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * distributed under the License is distributed on an "AS IS" BASIS, 12525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * See the License for the specific language governing permissions and 14525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * limitations under the License. 15525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov */ 16525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 17525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovpackage com.android.printspooler.model; 18525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 19525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport android.util.Log; 20525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 21525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport java.io.File; 22525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovimport java.io.IOException; 23525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 24525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov/** 25525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * This class provides a shared file to several threads. Only one thread 26525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * at a time can use the file. To acquire the file a thread has to 27525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * request it in a blocking call to {@link #acquireFile(OnReleaseRequestCallback)}. 28525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * The provided callback is optional and is used to notify the owning thread 29525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * when another one wants to acquire the file. In case a release is requested 30525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * the thread owning the file must release it as soon as possible. If no 31525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * callback is provided a thread that acquires the file must release it 32525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * as soon as possible, i.e. even if callback was provided the thread cannot 33525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * have the file for less time. 34525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov */ 35525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovpublic final class MutexFileProvider { 36525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private static final String LOG_TAG = "MutexFileProvider"; 37525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 38525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private static final boolean DEBUG = true; 39525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 40525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final Object mLock = new Object(); 41525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 42525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private final File mFile; 43525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 44525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private Thread mOwnerThread; 45525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 46525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov private OnReleaseRequestCallback mOnReleaseRequestCallback; 47525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 48525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public interface OnReleaseRequestCallback { 49525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void onReleaseRequested(File file); 50525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 51525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 52525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public MutexFileProvider(File file) throws IOException { 53525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mFile = file; 54525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (file.exists()) { 55525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov file.delete(); 56525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 57525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov file.createNewFile(); 58525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 59525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 60525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public File acquireFile(OnReleaseRequestCallback callback) { 61525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov synchronized (mLock) { 62525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // If this thread has the file, nothing to do. 63525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (mOwnerThread == Thread.currentThread()) { 64525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return mFile; 65525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 66525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 67525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // Another thread wants file ask for a release. 68525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (mOwnerThread != null && mOnReleaseRequestCallback != null) { 69525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mOnReleaseRequestCallback.onReleaseRequested(mFile); 70525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 71525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 72525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // Wait until the file is released. 73525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov while (mOwnerThread != null) { 74525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov try { 75525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mLock.wait(); 76525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } catch (InterruptedException ie) { 77525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov /* ignore */ 78525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 79525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 80525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 81525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // Update the owner and the callback. 82525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mOwnerThread = Thread.currentThread(); 83525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mOnReleaseRequestCallback = callback; 84525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 85525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (DEBUG) { 86525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Log.i(LOG_TAG, "Acquired file: " + mFile + " by thread: " + mOwnerThread); 87525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 88525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 89525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov return mFile; 90525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 91525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 92525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 93525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov public void releaseFile() { 94525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov synchronized (mLock) { 95525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (mOwnerThread != Thread.currentThread()) { 96cf3a86b55981313e1fdfafbef89ab5ba7276a862Svetoslav return; 97525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 98525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 99525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov if (DEBUG) { 100525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov Log.i(LOG_TAG, "Released file: " + mFile + " from thread: " + mOwnerThread); 101525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 102525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 103525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov // Update the owner and the callback. 104525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mOwnerThread = null; 105525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mOnReleaseRequestCallback = null; 106525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov 107525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov mLock.notifyAll(); 108525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 109525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov } 110525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov} 111