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 }