1/* 2 * Copyright (C) 2016 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 17package com.android.server.autofill; 18 19import static com.android.server.autofill.AutofillManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS; 20 21import android.os.Bundle; 22import android.os.ShellCommand; 23import android.os.UserHandle; 24import android.view.autofill.AutofillManager; 25 26import com.android.internal.os.IResultReceiver; 27 28import java.io.PrintWriter; 29import java.util.ArrayList; 30import java.util.concurrent.CountDownLatch; 31import java.util.concurrent.TimeUnit; 32 33public final class AutofillManagerServiceShellCommand extends ShellCommand { 34 35 private final AutofillManagerService mService; 36 37 public AutofillManagerServiceShellCommand(AutofillManagerService service) { 38 mService = service; 39 } 40 41 @Override 42 public int onCommand(String cmd) { 43 if (cmd == null) { 44 return handleDefaultCommands(cmd); 45 } 46 final PrintWriter pw = getOutPrintWriter(); 47 switch (cmd) { 48 case "list": 49 return requestList(pw); 50 case "destroy": 51 return requestDestroy(pw); 52 case "reset": 53 return requestReset(); 54 case "get": 55 return requestGet(pw); 56 case "set": 57 return requestSet(pw); 58 default: 59 return handleDefaultCommands(cmd); 60 } 61 } 62 63 @Override 64 public void onHelp() { 65 try (final PrintWriter pw = getOutPrintWriter();) { 66 pw.println("AutoFill Service (autofill) commands:"); 67 pw.println(" help"); 68 pw.println(" Prints this help text."); 69 pw.println(""); 70 pw.println(" get log_level "); 71 pw.println(" Gets the Autofill log level (off | debug | verbose)."); 72 pw.println(""); 73 pw.println(" get max_partitions"); 74 pw.println(" Gets the maximum number of partitions per session."); 75 pw.println(""); 76 pw.println(" set log_level [off | debug | verbose]"); 77 pw.println(" Sets the Autofill log level."); 78 pw.println(""); 79 pw.println(" set max_partitions number"); 80 pw.println(" Sets the maximum number of partitions per session."); 81 pw.println(""); 82 pw.println(" list sessions [--user USER_ID]"); 83 pw.println(" List all pending sessions."); 84 pw.println(""); 85 pw.println(" destroy sessions [--user USER_ID]"); 86 pw.println(" Destroy all pending sessions."); 87 pw.println(""); 88 pw.println(" reset"); 89 pw.println(" Reset all pending sessions and cached service connections."); 90 pw.println(""); 91 } 92 } 93 94 private int requestGet(PrintWriter pw) { 95 final String what = getNextArgRequired(); 96 switch(what) { 97 case "log_level": 98 return getLogLevel(pw); 99 case "max_partitions": 100 return getMaxPartitions(pw); 101 default: 102 pw.println("Invalid set: " + what); 103 return -1; 104 } 105 } 106 107 private int requestSet(PrintWriter pw) { 108 final String what = getNextArgRequired(); 109 110 switch(what) { 111 case "log_level": 112 return setLogLevel(pw); 113 case "max_partitions": 114 return setMaxPartitions(); 115 default: 116 pw.println("Invalid set: " + what); 117 return -1; 118 } 119 } 120 121 private int getLogLevel(PrintWriter pw) { 122 final int logLevel = mService.getLogLevel(); 123 switch (logLevel) { 124 case AutofillManager.FLAG_ADD_CLIENT_VERBOSE: 125 pw.println("verbose"); 126 return 0; 127 case AutofillManager.FLAG_ADD_CLIENT_DEBUG: 128 pw.println("debug"); 129 return 0; 130 case 0: 131 pw.println("off"); 132 return 0; 133 default: 134 pw.println("unknow (" + logLevel + ")"); 135 return 0; 136 } 137 } 138 139 private int setLogLevel(PrintWriter pw) { 140 final String logLevel = getNextArgRequired(); 141 switch (logLevel.toLowerCase()) { 142 case "verbose": 143 mService.setLogLevel(AutofillManager.FLAG_ADD_CLIENT_VERBOSE); 144 return 0; 145 case "debug": 146 mService.setLogLevel(AutofillManager.FLAG_ADD_CLIENT_DEBUG); 147 return 0; 148 case "off": 149 mService.setLogLevel(0); 150 return 0; 151 default: 152 pw.println("Invalid level: " + logLevel); 153 return -1; 154 } 155 } 156 157 private int getMaxPartitions(PrintWriter pw) { 158 pw.println(mService.getMaxPartitions()); 159 return 0; 160 } 161 162 private int setMaxPartitions() { 163 mService.setMaxPartitions(Integer.parseInt(getNextArgRequired())); 164 return 0; 165 } 166 167 private int requestDestroy(PrintWriter pw) { 168 if (!isNextArgSessions(pw)) { 169 return -1; 170 } 171 172 final int userId = getUserIdFromArgsOrAllUsers(); 173 final CountDownLatch latch = new CountDownLatch(1); 174 final IResultReceiver receiver = new IResultReceiver.Stub() { 175 @Override 176 public void send(int resultCode, Bundle resultData) { 177 latch.countDown(); 178 } 179 }; 180 return requestSessionCommon(pw, latch, () -> mService.destroySessions(userId, receiver)); 181 } 182 183 private int requestList(PrintWriter pw) { 184 if (!isNextArgSessions(pw)) { 185 return -1; 186 } 187 188 final int userId = getUserIdFromArgsOrAllUsers(); 189 final CountDownLatch latch = new CountDownLatch(1); 190 final IResultReceiver receiver = new IResultReceiver.Stub() { 191 @Override 192 public void send(int resultCode, Bundle resultData) { 193 final ArrayList<String> sessions = resultData 194 .getStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS); 195 for (String session : sessions) { 196 pw.println(session); 197 } 198 latch.countDown(); 199 } 200 }; 201 return requestSessionCommon(pw, latch, () -> mService.listSessions(userId, receiver)); 202 } 203 204 private boolean isNextArgSessions(PrintWriter pw) { 205 final String type = getNextArgRequired(); 206 if (!type.equals("sessions")) { 207 pw.println("Error: invalid list type"); 208 return false; 209 } 210 return true; 211 } 212 213 private boolean isNextArgLogLevel(PrintWriter pw, String cmd) { 214 final String type = getNextArgRequired(); 215 if (!type.equals("log_level")) { 216 pw.println("Error: invalid " + cmd + " type: " + type); 217 return false; 218 } 219 return true; 220 } 221 222 private int requestSessionCommon(PrintWriter pw, CountDownLatch latch, 223 Runnable command) { 224 command.run(); 225 226 try { 227 final boolean received = latch.await(5, TimeUnit.SECONDS); 228 if (!received) { 229 pw.println("Timed out after 5 seconds"); 230 return -1; 231 } 232 } catch (InterruptedException e) { 233 pw.println("System call interrupted"); 234 Thread.currentThread().interrupt(); 235 return -1; 236 } 237 return 0; 238 } 239 240 private int requestReset() { 241 mService.reset(); 242 return 0; 243 } 244 245 private int getUserIdFromArgsOrAllUsers() { 246 if ("--user".equals(getNextArg())) { 247 return UserHandle.parseUserArg(getNextArgRequired()); 248 } 249 return UserHandle.USER_ALL; 250 } 251} 252