1 /* 2 * Copyright (C) 2021 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.statusbar.policy 18 19 import android.content.Context 20 import android.content.pm.UserInfo 21 import android.database.ContentObserver 22 import android.net.Uri 23 import android.os.Handler 24 import android.os.HandlerExecutor 25 import android.os.UserHandle 26 import android.provider.Settings 27 import android.util.ArraySet 28 import android.util.SparseBooleanArray 29 import androidx.annotation.GuardedBy 30 import androidx.annotation.WorkerThread 31 import com.android.systemui.Dumpable 32 import com.android.systemui.dagger.SysUISingleton 33 import com.android.systemui.dagger.qualifiers.Background 34 import com.android.systemui.dagger.qualifiers.Main 35 import com.android.systemui.dump.DumpManager 36 import com.android.systemui.settings.UserTracker 37 import com.android.systemui.util.settings.GlobalSettings 38 import com.android.systemui.util.settings.SecureSettings 39 import java.io.PrintWriter 40 import java.util.concurrent.Executor 41 import java.util.concurrent.atomic.AtomicBoolean 42 import javax.inject.Inject 43 44 @SysUISingleton 45 open class DeviceProvisionedControllerImpl @Inject constructor( 46 private val secureSettings: SecureSettings, 47 private val globalSettings: GlobalSettings, 48 private val userTracker: UserTracker, 49 private val dumpManager: DumpManager, 50 @Background private val backgroundHandler: Handler, 51 @Main private val mainExecutor: Executor 52 ) : DeviceProvisionedController, 53 DeviceProvisionedController.DeviceProvisionedListener, 54 Dumpable { 55 56 companion object { 57 private const val ALL_USERS = -1 58 private const val NO_USERS = -2 59 protected const val TAG = "DeviceProvisionedControllerImpl" 60 } 61 62 private val deviceProvisionedUri = globalSettings.getUriFor(Settings.Global.DEVICE_PROVISIONED) 63 private val frpActiveUri = secureSettings.getUriFor(Settings.Secure.SECURE_FRP_MODE) 64 private val userSetupUri = secureSettings.getUriFor(Settings.Secure.USER_SETUP_COMPLETE) 65 66 private val deviceProvisioned = AtomicBoolean(false) 67 private val frpActive = AtomicBoolean(false) 68 @GuardedBy("lock") 69 private val userSetupComplete = SparseBooleanArray() 70 @GuardedBy("lock") 71 private val listeners = ArraySet<DeviceProvisionedController.DeviceProvisionedListener>() 72 73 private val lock = Any() 74 75 private val backgroundExecutor = HandlerExecutor(backgroundHandler) 76 77 private val initted = AtomicBoolean(false) 78 79 private val _currentUser: Int 80 get() = userTracker.userId 81 getCurrentUsernull82 override fun getCurrentUser(): Int { 83 return _currentUser 84 } 85 86 private val observer = object : ContentObserver(backgroundHandler) { onChangenull87 override fun onChange( 88 selfChange: Boolean, 89 uris: MutableCollection<Uri>, 90 flags: Int, 91 userId: Int 92 ) { 93 val updateDeviceProvisioned = deviceProvisionedUri in uris 94 val updateFrp = frpActiveUri in uris 95 val updateUser = if (userSetupUri in uris) userId else NO_USERS 96 updateValues(updateDeviceProvisioned, updateFrp, updateUser) 97 if (updateDeviceProvisioned) { 98 onDeviceProvisionedChanged() 99 } 100 if (updateFrp) { 101 onFrpActiveChanged() 102 } 103 if (updateUser != NO_USERS) { 104 onUserSetupChanged() 105 } 106 } 107 } 108 109 private val userChangedCallback = object : UserTracker.Callback { 110 @WorkerThread onUserChangednull111 override fun onUserChanged(newUser: Int, userContext: Context) { 112 updateValues(updateDeviceProvisioned = false, updateFrp = false, updateUser = newUser) 113 onUserSwitched() 114 } 115 onProfilesChangednull116 override fun onProfilesChanged(profiles: List<UserInfo>) {} 117 } 118 119 init { 120 userSetupComplete.put(currentUser, false) 121 } 122 123 /** 124 * Call to initialize values and register observers 125 */ initnull126 open fun init() { 127 if (!initted.compareAndSet(false, true)) { 128 return 129 } 130 dumpManager.registerDumpable(this) 131 updateValues() 132 userTracker.addCallback(userChangedCallback, backgroundExecutor) 133 globalSettings.registerContentObserver(deviceProvisionedUri, observer) 134 globalSettings.registerContentObserver(frpActiveUri, observer) 135 secureSettings.registerContentObserverForUser(userSetupUri, observer, UserHandle.USER_ALL) 136 } 137 138 @WorkerThread updateValuesnull139 private fun updateValues( 140 updateDeviceProvisioned: Boolean = true, 141 updateFrp: Boolean = true, 142 updateUser: Int = ALL_USERS 143 ) { 144 if (updateDeviceProvisioned) { 145 deviceProvisioned 146 .set(globalSettings.getInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0) 147 } 148 if (updateFrp) { 149 frpActive.set(globalSettings.getInt(Settings.Secure.SECURE_FRP_MODE, 0) != 0) 150 } 151 synchronized(lock) { 152 if (updateUser == ALL_USERS) { 153 val n = userSetupComplete.size() 154 for (i in 0 until n) { 155 val user = userSetupComplete.keyAt(i) 156 val value = secureSettings 157 .getIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, user) != 0 158 userSetupComplete.put(user, value) 159 } 160 } else if (updateUser != NO_USERS) { 161 val value = secureSettings 162 .getIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, updateUser) != 0 163 userSetupComplete.put(updateUser, value) 164 } 165 } 166 } 167 168 /** 169 * Adds a listener. 170 * 171 * The listener will not be called when this happens. 172 */ addCallbacknull173 override fun addCallback(listener: DeviceProvisionedController.DeviceProvisionedListener) { 174 synchronized(lock) { 175 listeners.add(listener) 176 } 177 } 178 removeCallbacknull179 override fun removeCallback(listener: DeviceProvisionedController.DeviceProvisionedListener) { 180 synchronized(lock) { 181 listeners.remove(listener) 182 } 183 } 184 isDeviceProvisionednull185 override fun isDeviceProvisioned(): Boolean { 186 return deviceProvisioned.get() 187 } 188 isFrpActivenull189 override fun isFrpActive(): Boolean { 190 return frpActive.get() 191 } 192 isUserSetupnull193 override fun isUserSetup(user: Int): Boolean { 194 val index = synchronized(lock) { 195 userSetupComplete.indexOfKey(user) 196 } 197 return if (index < 0) { 198 val value = secureSettings 199 .getIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, user) != 0 200 synchronized(lock) { 201 userSetupComplete.put(user, value) 202 } 203 value 204 } else { 205 synchronized(lock) { 206 userSetupComplete.get(user, false) 207 } 208 } 209 } 210 isCurrentUserSetupnull211 override fun isCurrentUserSetup(): Boolean { 212 return isUserSetup(currentUser) 213 } 214 onDeviceProvisionedChangednull215 override fun onDeviceProvisionedChanged() { 216 dispatchChange( 217 DeviceProvisionedController.DeviceProvisionedListener::onDeviceProvisionedChanged 218 ) 219 } 220 onFrpActiveChangednull221 override fun onFrpActiveChanged() { 222 dispatchChange( 223 DeviceProvisionedController.DeviceProvisionedListener::onFrpActiveChanged 224 ) 225 } 226 onUserSetupChangednull227 override fun onUserSetupChanged() { 228 dispatchChange(DeviceProvisionedController.DeviceProvisionedListener::onUserSetupChanged) 229 } 230 onUserSwitchednull231 override fun onUserSwitched() { 232 dispatchChange(DeviceProvisionedController.DeviceProvisionedListener::onUserSwitched) 233 } 234 dispatchChangenull235 protected fun dispatchChange( 236 callback: DeviceProvisionedController.DeviceProvisionedListener.() -> Unit 237 ) { 238 val listenersCopy = synchronized(lock) { 239 ArrayList(listeners) 240 } 241 mainExecutor.execute { 242 listenersCopy.forEach(callback) 243 } 244 } 245 dumpnull246 override fun dump(pw: PrintWriter, args: Array<out String>) { 247 pw.println("Device provisioned: ${deviceProvisioned.get()}") 248 pw.println("Factory Reset Protection active: ${frpActive.get()}") 249 synchronized(lock) { 250 pw.println("User setup complete: $userSetupComplete") 251 pw.println("Listeners: $listeners") 252 } 253 } 254 }