1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.printspooler.model; 18 19 import android.util.Log; 20 21 import java.io.File; 22 import java.io.IOException; 23 24 /** 25 * This class provides a shared file to several threads. Only one thread 26 * at a time can use the file. To acquire the file a thread has to 27 * request it in a blocking call to {@link #acquireFile(OnReleaseRequestCallback)}. 28 * The provided callback is optional and is used to notify the owning thread 29 * when another one wants to acquire the file. In case a release is requested 30 * the thread owning the file must release it as soon as possible. If no 31 * callback is provided a thread that acquires the file must release it 32 * as soon as possible, i.e. even if callback was provided the thread cannot 33 * have the file for less time. 34 */ 35 public final class MutexFileProvider { 36 private static final String LOG_TAG = "MutexFileProvider"; 37 38 private static final boolean DEBUG = true; 39 40 private final Object mLock = new Object(); 41 42 private final File mFile; 43 44 private Thread mOwnerThread; 45 46 private OnReleaseRequestCallback mOnReleaseRequestCallback; 47 48 public interface OnReleaseRequestCallback { onReleaseRequested(File file)49 public void onReleaseRequested(File file); 50 } 51 MutexFileProvider(File file)52 public MutexFileProvider(File file) throws IOException { 53 mFile = file; 54 if (file.exists()) { 55 file.delete(); 56 } 57 file.createNewFile(); 58 } 59 acquireFile(OnReleaseRequestCallback callback)60 public File acquireFile(OnReleaseRequestCallback callback) { 61 synchronized (mLock) { 62 // If this thread has the file, nothing to do. 63 if (mOwnerThread == Thread.currentThread()) { 64 return mFile; 65 } 66 67 // Another thread wants file ask for a release. 68 if (mOwnerThread != null && mOnReleaseRequestCallback != null) { 69 mOnReleaseRequestCallback.onReleaseRequested(mFile); 70 } 71 72 // Wait until the file is released. 73 while (mOwnerThread != null) { 74 try { 75 mLock.wait(); 76 } catch (InterruptedException ie) { 77 /* ignore */ 78 } 79 } 80 81 // Update the owner and the callback. 82 mOwnerThread = Thread.currentThread(); 83 mOnReleaseRequestCallback = callback; 84 85 if (DEBUG) { 86 Log.i(LOG_TAG, "Acquired file: " + mFile + " by thread: " + mOwnerThread); 87 } 88 89 return mFile; 90 } 91 } 92 releaseFile()93 public void releaseFile() { 94 synchronized (mLock) { 95 if (mOwnerThread != Thread.currentThread()) { 96 return; 97 } 98 99 if (DEBUG) { 100 Log.i(LOG_TAG, "Released file: " + mFile + " from thread: " + mOwnerThread); 101 } 102 103 // Update the owner and the callback. 104 mOwnerThread = null; 105 mOnReleaseRequestCallback = null; 106 107 mLock.notifyAll(); 108 } 109 } 110 } 111