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.car.admin; 18 19 import static com.android.car.PermissionHelper.checkHasDumpPermissionGranted; 20 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.DUMP_INFO; 21 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.UserIdInt; 26 import android.app.ActivityManager; 27 import android.app.admin.DevicePolicyManager; 28 import android.car.admin.CarDevicePolicyManager; 29 import android.car.admin.ICarDevicePolicyService; 30 import android.car.builtin.os.UserManagerHelper; 31 import android.car.builtin.util.Slogf; 32 import android.car.user.UserCreationRequest; 33 import android.car.user.UserCreationResult; 34 import android.car.user.UserRemovalResult; 35 import android.car.user.UserStartResult; 36 import android.car.user.UserStopResult; 37 import android.car.util.concurrent.AndroidFuture; 38 import android.content.BroadcastReceiver; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.IntentFilter; 42 import android.content.pm.PackageManager; 43 import android.os.UserHandle; 44 import android.os.UserManager; 45 import android.util.SparseIntArray; 46 import android.util.proto.ProtoOutputStream; 47 48 import com.android.car.BuiltinPackageDependency; 49 import com.android.car.CarLog; 50 import com.android.car.CarServiceBase; 51 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport; 52 import com.android.car.internal.ResultCallbackImpl; 53 import com.android.car.internal.common.UserHelperLite; 54 import com.android.car.internal.os.CarSystemProperties; 55 import com.android.car.internal.util.DebugUtils; 56 import com.android.car.internal.util.IndentingPrintWriter; 57 import com.android.car.user.CarUserService; 58 import com.android.internal.annotations.GuardedBy; 59 import com.android.internal.annotations.VisibleForTesting; 60 61 import java.lang.annotation.Retention; 62 import java.lang.annotation.RetentionPolicy; 63 64 /** 65 * Service for device policy related features. 66 */ 67 public final class CarDevicePolicyService extends ICarDevicePolicyService.Stub 68 implements CarServiceBase { 69 70 @VisibleForTesting 71 static final String TAG = CarLog.tagFor(CarDevicePolicyService.class); 72 73 private static final int HAL_TIMEOUT_MS = CarSystemProperties.getUserHalTimeout().orElse(5_000); 74 private static final String PREFIX_NEW_USER_DISCLAIMER_STATUS = "NEW_USER_DISCLAIMER_STATUS_"; 75 76 // TODO(b/175057848) must be public because of DebugUtils.constantToString() 77 public static final int NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED = 0; 78 public static final int NEW_USER_DISCLAIMER_STATUS_RECEIVED = 1; 79 public static final int NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT = 2; 80 public static final int NEW_USER_DISCLAIMER_STATUS_SHOWN = 3; 81 public static final int NEW_USER_DISCLAIMER_STATUS_ACKED = 4; 82 83 private final Object mLock = new Object(); 84 private final CarUserService mCarUserService; 85 private final Context mContext; 86 private final Context mCarServiceBuiltinPackageContext; 87 88 @Retention(RetentionPolicy.SOURCE) 89 @IntDef(flag = false, prefix = { PREFIX_NEW_USER_DISCLAIMER_STATUS }, value = { 90 NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED, 91 NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT, 92 NEW_USER_DISCLAIMER_STATUS_RECEIVED, 93 NEW_USER_DISCLAIMER_STATUS_SHOWN, 94 NEW_USER_DISCLAIMER_STATUS_ACKED 95 }) 96 public @interface NewUserDisclaimerStatus {} 97 98 @GuardedBy("mLock") 99 private final SparseIntArray mUserDisclaimerStatusPerUser = new SparseIntArray(); 100 101 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 102 @Override 103 public void onReceive(Context context, Intent intent) { 104 int userId = ActivityManager.getCurrentUser(); 105 Slogf.d(TAG, "Received intent for user " + userId + ": " + intent); 106 if (!mContext.getPackageManager() 107 .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) { 108 Slogf.d(TAG, "Not handling ACTION_SHOW_NEW_USER_DISCLAIMER because device " 109 + "doesn't have %s", PackageManager.FEATURE_DEVICE_ADMIN); 110 return; 111 } 112 switch(intent.getAction()) { 113 case DevicePolicyManager.ACTION_SHOW_NEW_USER_DISCLAIMER: 114 Slogf.d(TAG, "Action show new user disclaimer"); 115 setUserDisclaimerStatus(userId, NEW_USER_DISCLAIMER_STATUS_RECEIVED); 116 showNewUserDisclaimer(userId); 117 break; 118 default: 119 Slogf.w(TAG, "received unexpected intent: %s" , intent); 120 } 121 } 122 }; 123 CarDevicePolicyService(@onNull Context context, @NonNull Context carServiceBuiltinPackageContext, @NonNull CarUserService carUserService)124 public CarDevicePolicyService(@NonNull Context context, 125 @NonNull Context carServiceBuiltinPackageContext, 126 @NonNull CarUserService carUserService) { 127 mCarUserService = carUserService; 128 mContext = context; 129 mCarServiceBuiltinPackageContext = carServiceBuiltinPackageContext; 130 } 131 132 @Override init()133 public void init() { 134 Slogf.d(TAG, "init()"); 135 mContext.registerReceiverForAllUsers(mBroadcastReceiver, 136 new IntentFilter(DevicePolicyManager.ACTION_SHOW_NEW_USER_DISCLAIMER), 137 /* broadcastPermissions= */ null, /* scheduler= */ null, 138 Context.RECEIVER_NOT_EXPORTED); 139 } 140 141 @Override release()142 public void release() { 143 Slogf.d(TAG, "release()"); 144 mContext.unregisterReceiver(mBroadcastReceiver); 145 } 146 147 @Override removeUser(@serIdInt int userId, ResultCallbackImpl<UserRemovalResult> callback)148 public void removeUser(@UserIdInt int userId, ResultCallbackImpl<UserRemovalResult> callback) { 149 mCarUserService.removeUser(userId, /* hasCallerRestrictions= */ true, callback); 150 } 151 152 @Override createUser(@ullable String name, @CarDevicePolicyManager.UserType int type, ResultCallbackImpl<UserCreationResult> callback)153 public void createUser(@Nullable String name, @CarDevicePolicyManager.UserType int type, 154 ResultCallbackImpl<UserCreationResult> callback) { 155 UserCreationRequest.Builder userCreationRequestBuilder = 156 new UserCreationRequest.Builder().setName(name); 157 int userInfoFlags = 0; 158 String userType = UserManager.USER_TYPE_FULL_SECONDARY; 159 switch(type) { 160 case CarDevicePolicyManager.USER_TYPE_REGULAR: 161 break; 162 case CarDevicePolicyManager.USER_TYPE_ADMIN: 163 userInfoFlags = UserManagerHelper.FLAG_ADMIN; 164 userCreationRequestBuilder.setAdmin(); 165 break; 166 case CarDevicePolicyManager.USER_TYPE_GUEST: 167 userType = UserManager.USER_TYPE_FULL_GUEST; 168 userCreationRequestBuilder.setGuest(); 169 break; 170 default: 171 Slogf.d(TAG, "createUser(): invalid userType (%s) / flags (%08x) " 172 + "combination", userType, userInfoFlags); 173 callback.complete( 174 new UserCreationResult(UserCreationResult.STATUS_INVALID_REQUEST)); 175 return; 176 } 177 178 Slogf.d(TAG, "calling createUser(%s, %s, %d, %d)", 179 UserHelperLite.safeName(name), userType, userInfoFlags, HAL_TIMEOUT_MS); 180 181 mCarUserService.createUser(userCreationRequestBuilder.build(), HAL_TIMEOUT_MS, 182 callback); 183 } 184 185 @Override startUserInBackground(@serIdInt int userId, AndroidFuture<UserStartResult> receiver)186 public void startUserInBackground(@UserIdInt int userId, 187 AndroidFuture<UserStartResult> receiver) { 188 mCarUserService.startUserInBackground(userId, receiver); 189 } 190 191 @Override stopUser(@serIdInt int userId, AndroidFuture<UserStopResult> receiver)192 public void stopUser(@UserIdInt int userId, AndroidFuture<UserStopResult> receiver) { 193 mCarUserService.stopUser(userId, receiver); 194 } 195 196 @Override 197 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dump(@onNull IndentingPrintWriter writer)198 public void dump(@NonNull IndentingPrintWriter writer) { 199 checkHasDumpPermissionGranted(mContext, "dump()"); 200 201 writer.println("*CarDevicePolicyService*"); 202 203 synchronized (mLock) { 204 int numUsers = mUserDisclaimerStatusPerUser.size(); 205 writer.println("**mDisclaimerStatusPerUser**"); 206 for (int i = 0; i < numUsers; i++) { 207 int userId = mUserDisclaimerStatusPerUser.keyAt(i); 208 int status = mUserDisclaimerStatusPerUser.get(userId); 209 writer.printf("userId=%d disclaimerStatus=%s\n", userId, 210 newUserDisclaimerStatusToString(status)); 211 } 212 } 213 214 writer.printf("HAL_TIMEOUT_MS: %d\n", HAL_TIMEOUT_MS); 215 } 216 217 @Override 218 @ExcludeFromCodeCoverageGeneratedReport(reason = DUMP_INFO) dumpProto(ProtoOutputStream proto)219 public void dumpProto(ProtoOutputStream proto) {} 220 221 /** 222 * Updates the internal state with the disclaimer status as shown. 223 */ 224 @Override setUserDisclaimerShown(int userId)225 public void setUserDisclaimerShown(int userId) { 226 setUserDisclaimerStatus(userId, NEW_USER_DISCLAIMER_STATUS_SHOWN); 227 } 228 229 /** 230 * Updates the internal state with the disclaimer status as acknowledged. 231 */ 232 @Override setUserDisclaimerAcknowledged(int userId)233 public void setUserDisclaimerAcknowledged(int userId) { 234 setUserDisclaimerStatus(userId, NEW_USER_DISCLAIMER_STATUS_ACKED); 235 UserHandle user = UserHandle.of(userId); 236 BuiltinPackageDependency.createNotificationHelper(mCarServiceBuiltinPackageContext) 237 .cancelUserDisclaimerNotification(user); 238 239 DevicePolicyManager dpm = mContext.createContextAsUser(user, 0) 240 .getSystemService(DevicePolicyManager.class); 241 dpm.acknowledgeNewUserDisclaimer(); 242 } 243 244 @VisibleForTesting 245 @NewUserDisclaimerStatus getNewUserDisclaimerStatus(int userId)246 int getNewUserDisclaimerStatus(int userId) { 247 synchronized (mLock) { 248 return mUserDisclaimerStatusPerUser.get(userId, 249 NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED); 250 } 251 } 252 showNewUserDisclaimer(@serIdInt int userId)253 private void showNewUserDisclaimer(@UserIdInt int userId) { 254 // TODO(b/175057848) persist status so it's shown again if car service crashes? 255 256 BuiltinPackageDependency.createNotificationHelper(mCarServiceBuiltinPackageContext) 257 .showUserDisclaimerNotification(UserHandle.of(userId)); 258 259 setUserDisclaimerStatus(userId, NEW_USER_DISCLAIMER_STATUS_NOTIFICATION_SENT); 260 } 261 setUserDisclaimerStatus(@serIdInt int userId, @NewUserDisclaimerStatus int status)262 private void setUserDisclaimerStatus(@UserIdInt int userId, 263 @NewUserDisclaimerStatus int status) { 264 synchronized (mLock) { 265 Slogf.d(TAG, "Changing status from %s to %s", 266 newUserDisclaimerStatusToString( 267 mUserDisclaimerStatusPerUser.get( 268 userId, NEW_USER_DISCLAIMER_STATUS_NEVER_RECEIVED)), 269 newUserDisclaimerStatusToString(status)); 270 mUserDisclaimerStatusPerUser.put(userId, status); 271 } 272 } 273 274 @VisibleForTesting newUserDisclaimerStatusToString(@ewUserDisclaimerStatus int status)275 static String newUserDisclaimerStatusToString(@NewUserDisclaimerStatus int status) { 276 return DebugUtils.constantToString(CarDevicePolicyService.class, 277 PREFIX_NEW_USER_DISCLAIMER_STATUS, status); 278 } 279 } 280