• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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