1 /* 2 * Copyright (C) 2019 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.systemui 18 19 import android.util.Log 20 import com.android.internal.annotations.GuardedBy 21 import com.android.systemui.dagger.SysUISingleton 22 import com.android.systemui.dump.DumpManager 23 import java.io.PrintWriter 24 import java.lang.ref.WeakReference 25 import java.util.concurrent.atomic.AtomicBoolean 26 import javax.inject.Inject 27 28 /** 29 * Caches whether the device has reached [SystemService.PHASE_BOOT_COMPLETED]. 30 * 31 * This class is constructed and set by [SystemUIApplication] and will notify all listeners when 32 * boot is completed. 33 */ 34 @SysUISingleton 35 class BootCompleteCacheImpl @Inject constructor(dumpManager: DumpManager) : 36 BootCompleteCache, Dumpable { 37 38 companion object { 39 private const val TAG = "BootCompleteCacheImpl" 40 private const val DEBUG = false 41 } 42 43 init { 44 dumpManager.registerDumpable(TAG, this) 45 } 46 47 @GuardedBy("listeners") 48 private val listeners = mutableListOf<WeakReference<BootCompleteCache.BootCompleteListener>>() 49 private val bootComplete = AtomicBoolean(false) 50 51 /** 52 * Provides the current boot state of the system as determined by [SystemUIApplication]. 53 * @return `true` if the system has reached [SystemService.PHASE_BOOT_COMPLETED] 54 */ isBootCompletenull55 override fun isBootComplete(): Boolean = bootComplete.get() 56 57 /** 58 * Indicates to this object that boot is complete. Subsequent calls to this function will have 59 * no effect. 60 */ 61 fun setBootComplete() { 62 if (bootComplete.compareAndSet(false, true)) { 63 if (DEBUG) Log.d(TAG, "Boot complete set") 64 synchronized(listeners) { 65 listeners.forEach { 66 it.get()?.onBootComplete() 67 } 68 listeners.clear() 69 } 70 } 71 } 72 73 /** 74 * Add a listener for boot complete event. It will immediately return the current boot complete 75 * state. If this value is true, [BootCompleteCache.BootCompleteListener.onBootComplete] will 76 * never be called. 77 * 78 * @param listener a listener for boot complete state. 79 * @return `true` if boot has been completed. 80 */ addListenernull81 override fun addListener(listener: BootCompleteCache.BootCompleteListener): Boolean { 82 if (bootComplete.get()) return true 83 synchronized(listeners) { 84 if (bootComplete.get()) return true 85 listeners.add(WeakReference(listener)) 86 if (DEBUG) Log.d(TAG, "Adding listener: $listener") 87 return false 88 } 89 } 90 91 /** 92 * Removes a listener for boot complete event. 93 * 94 * @param listener a listener to removed. 95 */ removeListenernull96 override fun removeListener(listener: BootCompleteCache.BootCompleteListener) { 97 if (bootComplete.get()) return 98 synchronized(listeners) { 99 listeners.removeIf { it.get() == null || it.get() === listener } 100 if (DEBUG) Log.d(TAG, "Removing listener: $listener") 101 } 102 } 103 dumpnull104 override fun dump(pw: PrintWriter, args: Array<out String>) { 105 pw.println("BootCompleteCache state:") 106 pw.println(" boot complete: ${isBootComplete()}") 107 if (!isBootComplete()) { 108 pw.println(" listeners:") 109 synchronized(listeners) { 110 listeners.forEach { 111 pw.println(" $it") 112 } 113 } 114 } 115 } 116 }