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