summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src/com/android/systemui/BootCompleteCacheImpl.kt
blob: 9eaf4c96c8962a595a0648fba57ee8e03a1110f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui

import android.util.Log
import com.android.internal.annotations.GuardedBy
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import java.io.FileDescriptor
import java.io.PrintWriter
import java.lang.ref.WeakReference
import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject

/**
 * Caches whether the device has reached [SystemService.PHASE_BOOT_COMPLETED].
 *
 * This class is constructed and set by [SystemUIApplication] and will notify all listeners when
 * boot is completed.
 */
@SysUISingleton
class BootCompleteCacheImpl @Inject constructor(dumpManager: DumpManager) :
        BootCompleteCache, Dumpable {

    companion object {
        private const val TAG = "BootCompleteCacheImpl"
        private const val DEBUG = false
    }

    init {
        dumpManager.registerDumpable(TAG, this)
    }

    @GuardedBy("listeners")
    private val listeners = mutableListOf<WeakReference<BootCompleteCache.BootCompleteListener>>()
    private val bootComplete = AtomicBoolean(false)

    /**
     * Provides the current boot state of the system as determined by [SystemUIApplication].
     * @return `true` if the system has reached [SystemService.PHASE_BOOT_COMPLETED]
     */
    override fun isBootComplete(): Boolean = bootComplete.get()

    /**
     * Indicates to this object that boot is complete. Subsequent calls to this function will have
     * no effect.
     */
    fun setBootComplete() {
        if (bootComplete.compareAndSet(false, true)) {
            if (DEBUG) Log.d(TAG, "Boot complete set")
            synchronized(listeners) {
                listeners.forEach {
                    it.get()?.onBootComplete()
                }
                listeners.clear()
            }
        }
    }

    /**
     * Add a listener for boot complete event. It will immediately return the current boot complete
     * state. If this value is true, [BootCompleteCache.BootCompleteListener.onBootComplete] will
     * never be called.
     *
     * @param listener a listener for boot complete state.
     * @return `true` if boot has been completed.
     */
    override fun addListener(listener: BootCompleteCache.BootCompleteListener): Boolean {
        if (bootComplete.get()) return true
        synchronized(listeners) {
            if (bootComplete.get()) return true
            listeners.add(WeakReference(listener))
            if (DEBUG) Log.d(TAG, "Adding listener: $listener")
            return false
        }
    }

    /**
     * Removes a listener for boot complete event.
     *
     * @param listener a listener to removed.
     */
    override fun removeListener(listener: BootCompleteCache.BootCompleteListener) {
        if (bootComplete.get()) return
        synchronized(listeners) {
            listeners.removeIf { it.get() == null || it.get() === listener }
            if (DEBUG) Log.d(TAG, "Removing listener: $listener")
        }
    }

    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
        pw.println("BootCompleteCache state:")
        pw.println("  boot complete: ${isBootComplete()}")
        if (!isBootComplete()) {
            pw.println("  listeners:")
            synchronized(listeners) {
                listeners.forEach {
                    pw.println("    $it")
                }
            }
        }
    }
}