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