1 /*
2  * Copyright (C) 2023 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.devicelockcontroller.storage;
18 
19 import static com.android.devicelockcontroller.storage.IGlobalParametersService.Stub.asInterface;
20 
21 import android.annotation.SuppressLint;
22 import android.content.ComponentName;
23 import android.content.Context;
24 
25 import androidx.annotation.GuardedBy;
26 import androidx.annotation.NonNull;
27 import androidx.annotation.Nullable;
28 import androidx.annotation.VisibleForTesting;
29 
30 import com.android.devicelockcontroller.DeviceLockControllerApplication;
31 import com.android.devicelockcontroller.common.DeviceLockConstants.DeviceProvisionState;
32 import com.android.devicelockcontroller.policy.DeviceStateController.DeviceState;
33 import com.android.devicelockcontroller.policy.FinalizationControllerImpl.FinalizationState;
34 
35 import com.google.common.util.concurrent.ListenableFuture;
36 import com.google.common.util.concurrent.ListeningExecutorService;
37 import com.google.common.util.concurrent.MoreExecutors;
38 
39 import java.util.concurrent.Executors;
40 
41 /**
42  * A class used to access Global Parameters from any user.
43  */
44 public final class GlobalParametersClient extends DlcClient {
45 
46     private static final Object sInstanceLock = new Object();
47 
48     @SuppressLint("StaticFieldLeak") // Only holds application context.
49     @GuardedBy("sInstanceLock")
50     private static GlobalParametersClient sClient;
51 
GlobalParametersClient(@onNull Context context, ListeningExecutorService executorService)52     private GlobalParametersClient(@NonNull Context context,
53             ListeningExecutorService executorService) {
54         super(context, new ComponentName(context, GlobalParametersService.class), executorService);
55     }
56 
57     /**
58      * Get the GlobalParametersClient singleton instance.
59      */
getInstance()60     public static GlobalParametersClient getInstance() {
61         return getInstance(DeviceLockControllerApplication.getAppContext(),
62                 /* executorService= */ null);
63     }
64 
65     /**
66      * Get the GlobalParametersClient singleton instance.
67      */
68     @VisibleForTesting
getInstance(Context appContext, @Nullable ListeningExecutorService executorService)69     public static GlobalParametersClient getInstance(Context appContext,
70             @Nullable ListeningExecutorService executorService) {
71         synchronized (sInstanceLock) {
72             if (sClient == null) {
73                 sClient = new GlobalParametersClient(
74                         appContext,
75                         executorService == null
76                                 ? MoreExecutors.listeningDecorator(Executors.newCachedThreadPool())
77                                 : executorService);
78             }
79             return sClient;
80         }
81     }
82 
83     /**
84      * Reset the Client singleton instance
85      */
86     @VisibleForTesting
reset()87     public static void reset() {
88         synchronized (sInstanceLock) {
89             if (sClient != null) {
90                 sClient.tearDown();
91                 sClient = null;
92             }
93         }
94     }
95 
96     /**
97      * Clear any existing global parameters.
98      * Note that this API can only be called in debuggable build for debugging purpose.
99      */
100     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
clear()101     public ListenableFuture<Void> clear() {
102         return call(() -> {
103             asInterface(getService()).clear();
104             return null;
105         });
106     }
107 
108     /**
109      * Dump current values of SetupParameters to logcat.
110      */
111     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
dump()112     public ListenableFuture<Void> dump() {
113         return call(() -> {
114             asInterface(getService()).dump();
115             return null;
116         });
117     }
118 
119     /**
120      * Checks if provision is ready.
121      *
122      * @return true if device is ready to be provisioned.
123      */
124     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
125     public ListenableFuture<Boolean> isProvisionReady() {
126         return call(() -> asInterface(getService()).isProvisionReady());
127     }
128 
129     /**
130      * Sets the value of whether this device is ready for provision.
131      *
132      * @param isProvisionReady new state of whether the device is ready for provision.
133      */
134     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
135     public ListenableFuture<Void> setProvisionReady(boolean isProvisionReady) {
136         return call(() -> {
137             asInterface(getService()).setProvisionReady(isProvisionReady);
138             return null;
139         });
140     }
141 
142     /**
143      * Gets the unique identifier that is registered to DeviceLock backend server.
144      *
145      * @return The registered device unique identifier; null if device has never checked in with
146      * backed server.
147      */
148     @Nullable
149     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
150     public ListenableFuture<String> getRegisteredDeviceId() {
151         return call(() -> asInterface(getService()).getRegisteredDeviceId());
152     }
153 
154     /**
155      * Set the unique identifier that is registered to DeviceLock backend server.
156      *
157      * @param registeredDeviceId The registered device unique identifier.
158      */
159     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
160     public ListenableFuture<Void> setRegisteredDeviceId(String registeredDeviceId) {
161         return call(() -> {
162             asInterface(getService()).setRegisteredDeviceId(registeredDeviceId);
163             return null;
164         });
165     }
166 
167     /**
168      * Check if provision should be forced.
169      *
170      * @return True if the provision should be forced without any delays.
171      */
172     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
173     public ListenableFuture<Boolean> isProvisionForced() {
174         return call(() -> asInterface(getService()).isProvisionForced());
175     }
176 
177     /**
178      * Set provision is forced
179      *
180      * @param isForced The new value of the forced provision flag.
181      */
182     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
183     public ListenableFuture<Void> setProvisionForced(boolean isForced) {
184         return call(() -> {
185             asInterface(getService()).setProvisionForced(isForced);
186             return null;
187         });
188     }
189 
190     /**
191      * Gets the current device state.
192      *
193      * @return current device state
194      */
195     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
196     public ListenableFuture<@DeviceState Integer> getDeviceState() {
197         return call(() -> asInterface(getService()).getDeviceState());
198     }
199 
200     /**
201      * Sets the current device state.
202      *
203      * @param state New state.
204      */
205     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
206     public ListenableFuture<Void> setDeviceState(@DeviceState int state) {
207         return call(() -> {
208             asInterface(getService()).setDeviceState(state);
209             return null;
210         });
211     }
212 
213     /**
214      * Gets the current {@link FinalizationState}.
215      *
216      * @return current finalization state
217      */
218     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
219     public ListenableFuture<@FinalizationState Integer> getFinalizationState() {
220         return call(() -> asInterface(getService()).getFinalizationState());
221     }
222 
223     /**
224      * Sets the current {@link FinalizationState}.
225      *
226      * @param state new finalization state
227      */
228     @SuppressWarnings("GuardedBy") // mLock already held in "call" (error prone).
229     public ListenableFuture<Void> setFinalizationState(@FinalizationState int state) {
230         return call(() -> {
231             asInterface(getService()).setFinalizationState(state);
232             return null;
233         });
234     }
235 
236     /**
237      * Get the last received provision state determined by device lock server.
238      *
239      * @return one of {@link DeviceProvisionState}.
240      */
241     public ListenableFuture<Integer> getLastReceivedProvisionState() {
242         return call(() -> asInterface(getService()).getLastReceivedProvisionState());
243     }
244 
245     /**
246      * Set the last received provision state determined by device lock server.
247      *
248      * @param provisionState The provision state determined by device lock server
249      */
250     public ListenableFuture<Void> setLastReceivedProvisionState(
251             @DeviceProvisionState int provisionState) {
252         return call(() -> {
253             asInterface(getService()).setLastReceivedProvisionState(provisionState);
254             return null;
255         });
256     }
257 }
258