1 package leakcanary.internal.activity.db
2 
3 import android.content.Context
4 import android.database.sqlite.SQLiteDatabase
5 import java.io.Closeable
6 
7 internal object ScopedLeaksDb {
8 
9   @Volatile
10   private lateinit var leaksDbHelper: LeaksDbHelper
11 
12   private val lock = Any()
13 
14   @Volatile
15   private var openCount: Int = 0
16 
readableDatabasenull17   fun <T> readableDatabase(context: Context, block: (SQLiteDatabase) -> T): T {
18     return open(context).use {
19       block(it.readableDatabase)
20     }
21   }
22 
writableDatabasenull23   fun <T> writableDatabase(context: Context, block: (SQLiteDatabase) -> T): T {
24     return open(context).use {
25       block(it.writableDatabase)
26     }
27   }
28 
opennull29   fun open(context: Context): DbOpener {
30     synchronized(lock) {
31       if (!::leaksDbHelper.isInitialized) {
32         leaksDbHelper = LeaksDbHelper(context.applicationContext)
33       }
34       openCount++
35       return DbOpener()
36     }
37   }
38 
39   class DbOpener : Closeable {
40 
41     private var closed = false
42 
43     val readableDatabase: SQLiteDatabase
44       get() {
45         checkClosed()
46         return leaksDbHelper.readableDatabase
47       }
48 
49     val writableDatabase: SQLiteDatabase
50       get() {
51         checkClosed()
52         return leaksDbHelper.writableDatabase
53       }
54 
closenull55     override fun close() {
56       synchronized(lock) {
57         checkClosed()
58         closed = true
59         openCount--
60         if (openCount == 0) {
61           // No one else needs this right now, let's close the database (will reopen on
62           // next use)
63           leaksDbHelper.close()
64         }
65       }
66     }
67 
checkClosednull68     private fun checkClosed() {
69       check(!closed) {
70         "Already closed"
71       }
72     }
73   }
74 }
75