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