1 /* 2 * Copyright (C) 2022 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 package com.android.car.testdpc; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.app.admin.DevicePolicyManager; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.os.Bundle; 24 import android.os.Process; 25 import android.os.UserHandle; 26 import android.os.UserManager; 27 import android.util.Log; 28 29 import com.android.car.testdpc.remotedpm.DevicePolicyManagerInterface; 30 31 import java.io.PrintWriter; 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.LinkedHashSet; 35 import java.util.List; 36 import java.util.Objects; 37 import java.util.Set; 38 39 final class DpcShellCommand { 40 41 private static final String TAG = DpcShellCommand.class.getSimpleName(); 42 43 private final Context mContext; 44 private final DevicePolicyManager mDpm; 45 private final ComponentName mAdmin; 46 private final PrintWriter mWriter; 47 private final String[] mArgs; 48 private final DpcFactory mDpcFactory; 49 50 private final DevicePolicyManagerInterface mDeviceOwner; 51 52 /* Args has to be at least of size 4 to account for cmd, ARG_USER, userID, key */ 53 private static final int ADD_USER_RESTRICTION_ARG_LEN = 4; 54 /* Command only has one argument */ 55 private static final int SINGLE_ARG = 2; 56 57 private static final String ARG_TARGET_USER = "--target-user"; 58 private static final String CMD_GET_AFFILIATION_IDS = "get-affiliation-ids"; 59 private static final String CMD_SET_AFFILIATION_IDS = "set-affiliation-ids"; 60 private static final String CMD_IS_USER_AFFILIATED = "is-user-affiliated"; 61 private static final String CMD_SHOW_AFFILIATED_USERS = "show-affiliated-users"; 62 private static final String CMD_ADD_USER_RESTRICTION = "add-user-restriction"; 63 private static final String CMD_CLR_USER_RESTRICTION = "clear-user-restriction"; 64 private static final String CMD_GET_USER_RESTRICTIONS = "get-user-restrictions"; 65 private static final String CMD_HELP = "help"; 66 private static final String CMD_REBOOT = "reboot"; 67 private static final String CMD_CREATE_AND_MANAGE_USER = "create-and-manage-user"; 68 private static final String CMD_REMOVE_USER = "remove-user"; 69 private static final String CMD_START_USER_BACKGROUND = "start-user-background"; 70 private static final String CMD_STOP_USER = "stop-user"; 71 DpcShellCommand(Context context, DpcFactory dpcFactory, PrintWriter writer, String[] args)72 DpcShellCommand(Context context, DpcFactory dpcFactory, PrintWriter writer, String[] args) { 73 mContext = context; 74 mDpm = context.getSystemService(DevicePolicyManager.class); 75 mAdmin = new ComponentName(context, DpcReceiver.class.getName()); 76 mWriter = writer; 77 mArgs = args; 78 mDpcFactory = dpcFactory; 79 80 Log.d(TAG, "user=" + Process.myUserHandle() + ", component=" + mAdmin 81 + ", command= " + Arrays.toString(args)); 82 83 mDeviceOwner = mDpcFactory.getDevicePolicyManager( 84 UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM) 85 ); 86 } 87 run()88 void run() { 89 if (mArgs.length == 0) { 90 mWriter.println("Missing cmd"); 91 return; 92 } 93 String cmd = mArgs[0]; 94 try { 95 switch (cmd) { 96 case CMD_HELP: 97 runHelp(); 98 break; 99 case CMD_ADD_USER_RESTRICTION: 100 runAddUserRestriction(); 101 break; 102 case CMD_CLR_USER_RESTRICTION: 103 runClearUserRestriction(); 104 break; 105 case CMD_GET_USER_RESTRICTIONS: 106 runGetUserRestrictions(); 107 break; 108 case CMD_IS_USER_AFFILIATED: 109 runIsUserAffiliated(); 110 break; 111 case CMD_GET_AFFILIATION_IDS: 112 runGetAffiliationIds(); 113 break; 114 case CMD_SET_AFFILIATION_IDS: 115 runSetAffiliationIds(); 116 break; 117 case CMD_REBOOT: 118 runReboot(); 119 break; 120 case CMD_CREATE_AND_MANAGE_USER: 121 runCreateAndManageUser(); 122 break; 123 case CMD_REMOVE_USER: 124 runRemoveUser(); 125 break; 126 case CMD_START_USER_BACKGROUND: 127 runStartUserBackground(); 128 break; 129 case CMD_STOP_USER: 130 runStopUser(); 131 break; 132 case CMD_SHOW_AFFILIATED_USERS: 133 runShowAffiliatedUsers(); 134 break; 135 default: 136 mWriter.println("Invalid command: " + cmd); 137 showHelp(); 138 return; 139 } 140 } catch (Exception e) { 141 mWriter.println("Failed to execute " + Arrays.toString(mArgs) + ": " + e); 142 Log.e(TAG, "Failed to execute " + Arrays.toString(mArgs), e); 143 return; 144 } 145 } 146 runHelp()147 private void runHelp() { 148 mWriter.printf("%s\n", CMD_HELP); 149 mWriter.println("\tList all available commands for device policy."); 150 mWriter.printf("%s %s <user_id> <key>\n", CMD_ADD_USER_RESTRICTION, ARG_TARGET_USER); 151 mWriter.println("\tSet a user restriction on the user with specified user_id with the"); 152 mWriter.println("\t given key."); 153 mWriter.printf("%s <key>\n", CMD_CLR_USER_RESTRICTION); 154 mWriter.println("\tClear a user restriction specified by the key."); 155 mWriter.printf("%s\n", CMD_GET_USER_RESTRICTIONS); 156 mWriter.println("\tDisplay all active user restrictions."); 157 mWriter.printf("%s (<affiliation-ids>)\n", CMD_SET_AFFILIATION_IDS); 158 mWriter.println("\tSet affiliation id(s) (space separated list of strings)"); 159 mWriter.println("\tfor a specified user. An empty list clears the ids."); 160 mWriter.printf("%s\n", CMD_GET_AFFILIATION_IDS); 161 mWriter.println("\tGet affiliation id(s) for a specified user."); 162 mWriter.printf("%s\n", CMD_IS_USER_AFFILIATED); 163 mWriter.println("\tReturns whether this user is affiliated with the device."); 164 mWriter.printf("%s\n", CMD_SHOW_AFFILIATED_USERS); 165 mWriter.println("\tLists all affiliated users."); 166 mWriter.printf("%s\n", CMD_REBOOT); 167 mWriter.println("\tReboots the device."); 168 mWriter.printf("%s <user_name>\n", CMD_CREATE_AND_MANAGE_USER); 169 mWriter.println("\tStarts a user in background."); 170 mWriter.printf("%s %s <user_id>\n", CMD_REMOVE_USER, ARG_TARGET_USER); 171 mWriter.println("\tRemoves the user specified by <user-id>."); 172 mWriter.printf("%s %s <user_id>\n", CMD_START_USER_BACKGROUND, ARG_TARGET_USER); 173 mWriter.println("\tStarts the user specified user <user-id> in background."); 174 mWriter.printf("%s %s <user_id>\n", CMD_STOP_USER, ARG_TARGET_USER); 175 mWriter.println("\tStops the user specified by <user-id>."); 176 } 177 runAddUserRestriction()178 private void runAddUserRestriction() { 179 Log.i(TAG, "Calling addUserRestriction()"); 180 181 if (mArgs.length != ADD_USER_RESTRICTION_ARG_LEN || !(Objects.equals(mArgs[1], 182 ARG_TARGET_USER))) { 183 showHelp(); 184 return; 185 } 186 187 UserHandle target = getUserHandleFromUserId(mArgs[2]); 188 if (target == null) { 189 showHelp(); 190 return; 191 } 192 193 String restriction = mArgs[3]; 194 195 // restriction on specified device or profile owner 196 DevicePolicyManagerInterface targetDpm = mDpcFactory.getDevicePolicyManager(target); 197 198 if (targetDpm == null) { 199 showHelp(); 200 return; 201 } 202 203 Log.d(TAG, targetDpm.getUser() + ": addUserRestriction(" + restriction + ")"); 204 205 targetDpm.addUserRestriction(restriction); 206 } 207 runClearUserRestriction()208 private void runClearUserRestriction() { 209 String restriction = mArgs[1]; 210 Log.i(TAG, "Calling clearUserRestriction(" + restriction + ")"); 211 mDpm.clearUserRestriction(mAdmin, restriction); 212 } 213 runGetUserRestrictions()214 private void runGetUserRestrictions() { 215 Bundle restrictions = mDpm.getUserRestrictions(mAdmin); 216 if (restrictions == null || restrictions.isEmpty()) { 217 mWriter.println("No restrictions."); 218 } else { 219 mWriter.printf("%d restriction(s): %s\n", restrictions.size(), 220 bundleToString(restrictions)); 221 } 222 } 223 runGetAffiliationIds()224 private void runGetAffiliationIds() { 225 Set<String> ids = mDpm.getAffiliationIds(mAdmin); 226 List<String> idsList = new ArrayList<String>(ids); 227 mWriter.printf("%d affiliation ids: ", ids.size()); 228 for (int i = 0; i < idsList.size(); i++) { 229 if (i == idsList.size() - 1) { 230 mWriter.printf("%s\n", idsList.get(i)); 231 } else { 232 mWriter.printf("%s, ", idsList.get(i)); 233 } 234 } 235 } 236 runSetAffiliationIds()237 private void runSetAffiliationIds() { 238 Set<String> idSet = new LinkedHashSet<String>(); 239 if (mArgs.length > 1) { 240 for (int i = 1; i < mArgs.length; i++) { 241 idSet.add(mArgs[i]); 242 } 243 } 244 Log.i(TAG, "setAffiliationIds(): ids=" + idSet); 245 mDpm.setAffiliationIds(mAdmin, idSet); 246 247 runGetAffiliationIds(); 248 } 249 runIsUserAffiliated()250 private void runIsUserAffiliated() { 251 mWriter.println(mDpm.isAffiliatedUser()); 252 } 253 runReboot()254 private void runReboot() { 255 Log.i(TAG, "Calling reboot()"); 256 mDeviceOwner.reboot(); 257 } 258 runCreateAndManageUser()259 private void runCreateAndManageUser() { 260 if (mArgs.length != SINGLE_ARG) { 261 showHelp(); 262 return; 263 } 264 String userId = mArgs[1]; 265 UserHandle user = mDpm.createAndManageUser(mAdmin, userId, mAdmin, 266 /* adminExtras= */ null, /* flags= */ 0); 267 mWriter.printf("Created user with id %s: %s\n", userId, user); 268 } 269 runRemoveUser()270 private void runRemoveUser() { 271 if (mArgs.length != 3 || !Objects.equals(mArgs[1], ARG_TARGET_USER)) { 272 showHelp(); 273 return; 274 } 275 String userId = mArgs[2]; 276 UserHandle user = UserHandle.of(Integer.parseInt(userId)); 277 boolean success = mDpm.removeUser(mAdmin, user); 278 mWriter.printf("User %s was removed: %b\n", userId, success); 279 } 280 runStartUserBackground()281 private void runStartUserBackground() { 282 if (mArgs.length != 3 || !Objects.equals(mArgs[1], ARG_TARGET_USER)) { 283 showHelp(); 284 return; 285 } 286 String userId = mArgs[2]; 287 UserHandle user = UserHandle.of(Integer.parseInt(userId)); 288 int status = mDpm.startUserInBackground(mAdmin, user); 289 processStatusCode(userId, status); 290 291 if (status == UserManager.USER_OPERATION_SUCCESS) { 292 mDpcFactory.addProfileOwnerDpm(user); 293 } 294 } 295 runStopUser()296 private void runStopUser() { 297 if (mArgs.length != 3 || !Objects.equals(mArgs[1], ARG_TARGET_USER)) { 298 showHelp(); 299 return; 300 } 301 String userId = mArgs[2]; 302 UserHandle user = UserHandle.of(Integer.parseInt(userId)); 303 int status = mDpm.stopUser(mAdmin, user); 304 processStatusCode(userId, status); 305 306 if (status == UserManager.USER_OPERATION_SUCCESS) { 307 mDpcFactory.removeProfileOwnerDpm(user); 308 } 309 } 310 runShowAffiliatedUsers()311 private void runShowAffiliatedUsers() { 312 mWriter.printf("Device Owner: %s\n", mDeviceOwner.getUser()); 313 mWriter.printf("Users with callable Dpms: %s\n", 314 mDpcFactory.getAllBoundUsers()); 315 mWriter.printf("Users with same affiliation ids: %s\n", 316 mDpm.getBindDeviceAdminTargetUsers(mAdmin)); 317 } 318 319 /** 320 * See {@link android.apps.gsa.shared.util.Util#bundleToString(Bundle)} 321 */ 322 @NonNull bundleToString(@onNull Bundle bundle)323 public static String bundleToString(@NonNull Bundle bundle) { 324 StringBuilder sb = new StringBuilder(); 325 sb.append('{'); 326 boolean first = true; 327 for (String key : bundle.keySet()) { 328 if (!first) { 329 sb.append(", "); 330 } 331 first = false; 332 Object value = bundle.get(key); 333 sb.append(key).append("=").append(value); 334 } 335 sb.append('}'); 336 return sb.toString(); 337 } 338 339 @Nullable getUserHandleFromUserId(String userId)340 public UserHandle getUserHandleFromUserId(String userId) { 341 UserHandle targetUser = null; 342 try { 343 targetUser = UserHandle.of(Integer.parseInt(userId)); 344 } catch (NumberFormatException e) { 345 mWriter.println("Could not parse target user id (see logs)"); 346 Log.e(TAG, "Could not parse target user id", e); 347 } 348 return targetUser; 349 } 350 showHelp()351 private void showHelp() { 352 mWriter.println("Incorrect calling format"); 353 mWriter.println("run 'help' to see the correct calling format"); 354 mWriter.printf("args: %s", Arrays.toString(mArgs)); 355 } 356 processStatusCode(String userId, int status)357 private void processStatusCode(String userId, int status) { 358 if (status == UserManager.USER_OPERATION_SUCCESS) { 359 mWriter.printf("Result of stopping user %s: success\n", 360 userId); 361 return; 362 } 363 364 mWriter.printf("Result of stopping user %s: error with code %d\n", 365 userId, status); 366 } 367 } 368