Home | History | Annotate | Download | only in async
      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.camera.async;
     18 
     19 import java.util.ArrayList;
     20 import java.util.HashSet;
     21 import java.util.List;
     22 import java.util.Set;
     23 
     24 /**
     25  * Enables handling the shut-down of components in a structured way.
     26  * <p>
     27  * Lifetimes are nestable sets of {@link SafeCloseable}s useful for guaranteeing
     28  * that resources, such as threads, files, hardware devices, etc., are properly
     29  * closed when necessary.
     30  * <p>
     31  * Child lifetimes are closed when their parent is closed, or when they are
     32  * closed directly, whichever comes first. Objects added to a particular
     33  * lifetime will only ever be closed once by that lifetime.
     34  * </p>
     35  */
     36 public class Lifetime implements SafeCloseable {
     37     /**
     38      * The parent, or null if there is no parent lifetime.
     39      */
     40     private final Lifetime mParent;
     41     private final Object mLock;
     42     private final Set<SafeCloseable> mCloseables;
     43     private boolean mClosed;
     44 
     45     public Lifetime() {
     46         mLock = new Object();
     47         mCloseables = new HashSet<SafeCloseable>();
     48         mParent = null;
     49         mClosed = false;
     50     }
     51 
     52     public Lifetime(Lifetime parent) {
     53         mLock = new Object();
     54         mCloseables = new HashSet<SafeCloseable>();
     55         mParent = parent;
     56         mClosed = false;
     57         parent.mCloseables.add(this);
     58     }
     59 
     60     /**
     61      * Adds the given object to this lifetime and returns it.
     62      */
     63     public <T extends SafeCloseable> T add(T closeable) {
     64         boolean needToClose = false;
     65         synchronized (mLock) {
     66             if (mClosed) {
     67                 needToClose = true;
     68             } else {
     69                 mCloseables.add(closeable);
     70             }
     71         }
     72         if (needToClose) {
     73             closeable.close();
     74         }
     75         return closeable;
     76     }
     77 
     78     @Override
     79     public void close() {
     80         List<SafeCloseable> toClose = new ArrayList<SafeCloseable>();
     81         synchronized (mLock) {
     82             if (mClosed) {
     83                 return;
     84             }
     85             mClosed = true;
     86             // Remove from parent to avoid leaking memory if a long-lasting
     87             // lifetime has lots of shorter-lived lifetimes created and
     88             // destroyed repeatedly.
     89             if (mParent != null) {
     90                 mParent.mCloseables.remove(this);
     91             }
     92             toClose.addAll(mCloseables);
     93             mCloseables.clear();
     94         }
     95         // Invoke close() outside the critical section
     96         for (SafeCloseable closeable : toClose) {
     97             closeable.close();
     98         }
     99     }
    100 }
    101