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