1 /*
2  * Copyright (C) 2020 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 android.car.admin;
18 
19 import static android.os.Process.myUid;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SuppressLint;
26 import android.annotation.SystemApi;
27 import android.annotation.TestApi;
28 import android.car.Car;
29 import android.car.CarManagerBase;
30 import android.car.SyncResultCallback;
31 import android.car.builtin.util.EventLogHelper;
32 import android.car.user.UserCreationResult;
33 import android.car.user.UserRemovalResult;
34 import android.car.user.UserStartResult;
35 import android.car.user.UserStopResult;
36 import android.car.util.concurrent.AndroidFuture;
37 import android.os.IBinder;
38 import android.os.RemoteException;
39 import android.os.UserHandle;
40 import android.util.Slog;
41 
42 import com.android.car.internal.ResultCallbackImpl;
43 import com.android.car.internal.common.UserHelperLite;
44 import com.android.car.internal.os.CarSystemProperties;
45 import com.android.internal.annotations.VisibleForTesting;
46 
47 import java.lang.annotation.Retention;
48 import java.lang.annotation.RetentionPolicy;
49 import java.util.Objects;
50 import java.util.concurrent.ExecutionException;
51 import java.util.concurrent.TimeUnit;
52 import java.util.concurrent.TimeoutException;
53 
54 /**
55  * Public interface for managing policies enforced on a device.
56  *
57  * <p>This is a sub-set of {@link android.app.admin.DevicePolicyManager}, but with the following
58  * differences:
59  *
60  * <ol>
61  *   <li>Its methods take in consideration driver-safety restrictions.
62  *   <li>Callers don't need to be a {@code DPC}, but rather have the proper permissions.
63  * </ol>
64  *
65  * @hide
66  */
67 @SystemApi
68 public final class CarDevicePolicyManager extends CarManagerBase {
69 
70     /**
71      * @hide
72      */
73     @VisibleForTesting
74     public static final String TAG = CarDevicePolicyManager.class.getSimpleName();
75 
76     private final ICarDevicePolicyService mService;
77 
78     private static final String PREFIX_USER_TYPE = "USER_TYPE_";
79 
80     /**
81      * Type used to indicate the user is a regular user.
82      */
83     public static final int USER_TYPE_REGULAR = 0;
84 
85     /**
86      * Type used to indicate the user is an admin user.
87      */
88     public static final int USER_TYPE_ADMIN = 1;
89 
90     /**
91      * Type used to indicate the user is a guest user.
92      */
93     public static final int USER_TYPE_GUEST = 2;
94 
95     /** @hide - Used on test cases only */
96     public static final int FIRST_USER_TYPE = USER_TYPE_REGULAR;
97     /** @hide - Used on test cases only */
98     public static final int LAST_USER_TYPE = USER_TYPE_GUEST;
99 
100     private static final int DEVICE_POLICY_MANAGER_TIMEOUT_MS =
101             CarSystemProperties.getDevicePolicyManagerTimeout().orElse(60_000);
102     private static final int REMOVE_USER_CALL_TIMEOUT_MS = 60_000;
103 
104     /** @hide */
105     @IntDef(prefix = PREFIX_USER_TYPE, value = {
106             USER_TYPE_REGULAR,
107             USER_TYPE_ADMIN,
108             USER_TYPE_GUEST
109     })
110     @Retention(RetentionPolicy.SOURCE)
111     public @interface UserType {
112     }
113 
114     /**
115      * @hide
116      */
CarDevicePolicyManager(@onNull Car car, @NonNull IBinder service)117     public CarDevicePolicyManager(@NonNull Car car, @NonNull IBinder service) {
118         this(car, ICarDevicePolicyService.Stub.asInterface(service));
119     }
120 
121     /**
122      * @hide
123      */
124     @VisibleForTesting
CarDevicePolicyManager(@onNull Car car, @NonNull ICarDevicePolicyService service)125     public CarDevicePolicyManager(@NonNull Car car, @NonNull ICarDevicePolicyService service) {
126         super(car);
127         mService = service;
128     }
129 
130     /**
131      * Removes the given user.
132      *
133      * <p><b>Note: </b>if the caller user is not an admin, it can only remove itself
134      * (otherwise it will fail with {@link RemoveUserResult#STATUS_FAILURE_INVALID_ARGUMENTS}).
135      *
136      * @param user identification of the user to be removed.
137      *
138      * @return whether the user was successfully removed.
139      *
140      * @hide
141      */
142     @SystemApi
143     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
144             android.Manifest.permission.CREATE_USERS})
145     @NonNull
146     @SuppressLint("VisibleForTests")
removeUser(@onNull UserHandle user)147     public RemoveUserResult removeUser(@NonNull UserHandle user) {
148         Objects.requireNonNull(user, "user cannot be null");
149 
150         int userId = user.getIdentifier();
151         int uid = myUid();
152         EventLogHelper.writeCarDevicePolicyManagerRemoveUserReq(uid, userId);
153         UserRemovalResult userRemovalResult = new UserRemovalResult(
154                 UserRemovalResult.STATUS_ANDROID_FAILURE);
155         try {
156             SyncResultCallback<UserRemovalResult> userRemovalResultCallback =
157                     new SyncResultCallback<>();
158             ResultCallbackImpl<UserRemovalResult> resultCallbackImpl = new ResultCallbackImpl<>(
159                     Runnable::run, userRemovalResultCallback);
160             mService.removeUser(user.getIdentifier(), resultCallbackImpl);
161 
162             userRemovalResult = userRemovalResultCallback.get(REMOVE_USER_CALL_TIMEOUT_MS,
163                     TimeUnit.MILLISECONDS);
164         } catch (InterruptedException e) {
165             Thread.currentThread().interrupt();
166             Slog.e(TAG, "CarDevicePolicyManager removeUser(user): ", e);
167         } catch (TimeoutException e) {
168             Slog.e(TAG, "CarDevicePolicyManager removeUser(user): ", e);
169         } catch (RemoteException e) {
170             return handleRemoteExceptionFromCarService(e,
171                     new RemoveUserResult(UserRemovalResult.STATUS_ANDROID_FAILURE));
172         } finally {
173             EventLogHelper.writeCarDevicePolicyManagerRemoveUserResp(uid,
174                     userRemovalResult.getStatus());
175         }
176         return new RemoveUserResult(userRemovalResult.getStatus());
177     }
178 
179     /**
180      * Creates a user with the given characteristics.
181      *
182      * <p><b>Note: </b>if the caller user is not an admin, it can only create non-admin users
183      * (otherwise it will fail with {@link CreateUserResult#STATUS_FAILURE_INVALID_ARGUMENTS}).
184      *
185      * @param name user name.
186      * @param type either {@link #USER_TYPE_REGULAR}, {@link #USER_TYPE_ADMIN},
187      * or {@link #USER_TYPE_GUEST}.
188      *
189      * @return whether the user was successfully removed.
190      *
191      * @hide
192      */
193     @SystemApi
194     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
195             android.Manifest.permission.CREATE_USERS})
196     @NonNull
createUser(@ullable String name, @UserType int type)197     public CreateUserResult createUser(@Nullable String name, @UserType int type) {
198         int uid = myUid();
199         EventLogHelper.writeCarDevicePolicyManagerCreateUserReq(uid, UserHelperLite.safeName(name),
200                 type);
201         int status = CreateUserResult.STATUS_FAILURE_GENERIC;
202         try {
203             SyncResultCallback<UserCreationResult> userCreationResultCallback =
204                     new SyncResultCallback<>();
205 
206             ResultCallbackImpl<UserCreationResult> resultCallbackImpl = new ResultCallbackImpl(
207                     Runnable::run, userCreationResultCallback);
208 
209             mService.createUser(name, type, resultCallbackImpl);
210 
211             UserCreationResult result = userCreationResultCallback.get(
212                     DEVICE_POLICY_MANAGER_TIMEOUT_MS, TimeUnit.MILLISECONDS);
213             status = result.getStatus();
214             return new CreateUserResult(result);
215         } catch (InterruptedException e) {
216             Thread.currentThread().interrupt();
217             return CreateUserResult.forGenericError();
218         } catch (TimeoutException e) {
219             return CreateUserResult.forGenericError();
220         } catch (RemoteException e) {
221             return handleRemoteExceptionFromCarService(e, CreateUserResult.forGenericError());
222         } finally {
223             EventLogHelper.writeCarDevicePolicyManagerCreateUserResp(uid, status);
224         }
225     }
226 
227     /**
228      * Starts a user in the background.
229      *
230      * @param user identification of the user to be started.
231      *
232      * @return whether the user was successfully started.
233      *
234      * @deprecated Use {@link android.car.user.CarUserManager#startUser(UserStartRequest)} instead.
235      * @hide
236      */
237     @TestApi
238     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
239             android.Manifest.permission.CREATE_USERS})
240     @NonNull
241     @Deprecated
startUserInBackground(@onNull UserHandle user)242     public StartUserInBackgroundResult startUserInBackground(@NonNull UserHandle user) {
243         Objects.requireNonNull(user, "user cannot be null");
244 
245         int userId = user.getIdentifier();
246         int uid = myUid();
247         EventLogHelper.writeCarDevicePolicyManagerStartUserInBackgroundReq(uid, userId);
248         int status = StartUserInBackgroundResult.STATUS_FAILURE_GENERIC;
249         try {
250             AndroidFuture<UserStartResult> future = new AndroidFuture<>();
251             mService.startUserInBackground(userId, future);
252             UserStartResult result = future.get(DEVICE_POLICY_MANAGER_TIMEOUT_MS,
253                     TimeUnit.MILLISECONDS);
254             status = result.getStatus();
255             return new StartUserInBackgroundResult(status);
256         } catch (InterruptedException e) {
257             Thread.currentThread().interrupt();
258             return new StartUserInBackgroundResult(status);
259         } catch (ExecutionException | TimeoutException e) {
260             return new StartUserInBackgroundResult(status);
261         } catch (RemoteException e) {
262             return handleRemoteExceptionFromCarService(e, new StartUserInBackgroundResult(status));
263         } finally {
264             EventLogHelper.writeCarDevicePolicyManagerStartUserInBackgroundResp(uid, status);
265         }
266     }
267 
268     /**
269      * Stops the given user.
270      *
271      * @param user identification of the user to stop.
272      *
273      * @return whether the user was successfully stopped.
274      *
275      * @hide
276      * @deprecated Use {@link android.car.user.CarUserManager#stopUser(UserStopRequest)} instead.
277      */
278     @TestApi
279     @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
280             android.Manifest.permission.CREATE_USERS})
281     @NonNull
282     @Deprecated
stopUser(@onNull UserHandle user)283     public StopUserResult stopUser(@NonNull UserHandle user) {
284         Objects.requireNonNull(user, "user cannot be null");
285 
286         int userId = user.getIdentifier();
287         int uid = myUid();
288         EventLogHelper.writeCarDevicePolicyManagerStopUserReq(uid, userId);
289         int status = StopUserResult.STATUS_FAILURE_GENERIC;
290         try {
291             AndroidFuture<UserStopResult> future = new AndroidFuture<>();
292             mService.stopUser(userId, future);
293             UserStopResult result =
294                     future.get(DEVICE_POLICY_MANAGER_TIMEOUT_MS, TimeUnit.MILLISECONDS);
295             status = result.getStatus();
296             return new StopUserResult(status);
297         } catch (InterruptedException e) {
298             Thread.currentThread().interrupt();
299             return new StopUserResult(status);
300         } catch (ExecutionException | TimeoutException e) {
301             return new StopUserResult(status);
302         } catch (RemoteException e) {
303             return handleRemoteExceptionFromCarService(e, new StopUserResult(status));
304         } finally {
305             EventLogHelper.writeCarDevicePolicyManagerStopUserResp(uid, status);
306         }
307     }
308 
309     /** @hide */
setUserDisclaimerShown(@onNull UserHandle user)310     public void setUserDisclaimerShown(@NonNull UserHandle user) {
311         Objects.requireNonNull(user, "user cannot be null");
312         try {
313             mService.setUserDisclaimerShown(user.getIdentifier());
314         } catch (RemoteException e) {
315             handleRemoteExceptionFromCarService(e, null);
316         }
317     }
318 
319     /** @hide */
setUserDisclaimerAcknowledged(@onNull UserHandle user)320     public void setUserDisclaimerAcknowledged(@NonNull UserHandle user) {
321         Objects.requireNonNull(user, "user cannot be null");
322         try {
323             mService.setUserDisclaimerAcknowledged(user.getIdentifier());
324         } catch (RemoteException e) {
325             handleRemoteExceptionFromCarService(e, null);
326         }
327     }
328 
329     /** @hide */
330     @Override
onCarDisconnected()331     public void onCarDisconnected() {
332         // nothing to do
333     }
334 }
335