Home | History | Annotate | Download | only in model
      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 {
     49         public void onReleaseRequested(File file);
     50     }
     51 
     52     public MutexFileProvider(File file) throws IOException {
     53         mFile = file;
     54         if (file.exists()) {
     55             file.delete();
     56         }
     57         file.createNewFile();
     58     }
     59 
     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 
     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