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 17 package com.android.server.autofill; 18 19 import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES; 20 import static android.service.autofill.AutofillService.EXTRA_RESULT; 21 22 import static com.android.server.autofill.AutofillManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS; 23 24 import android.os.Bundle; 25 import android.os.RemoteCallback; 26 import android.os.ShellCommand; 27 import android.os.UserHandle; 28 import android.service.autofill.AutofillFieldClassificationService.Scores; 29 import android.view.autofill.AutofillManager; 30 31 import com.android.internal.os.IResultReceiver; 32 33 import java.io.PrintWriter; 34 import java.util.ArrayList; 35 import java.util.concurrent.CountDownLatch; 36 import java.util.concurrent.TimeUnit; 37 38 public final class AutofillManagerServiceShellCommand extends ShellCommand { 39 40 private final AutofillManagerService mService; 41 AutofillManagerServiceShellCommand(AutofillManagerService service)42 public AutofillManagerServiceShellCommand(AutofillManagerService service) { 43 mService = service; 44 } 45 46 @Override onCommand(String cmd)47 public int onCommand(String cmd) { 48 if (cmd == null) { 49 return handleDefaultCommands(cmd); 50 } 51 final PrintWriter pw = getOutPrintWriter(); 52 switch (cmd) { 53 case "list": 54 return requestList(pw); 55 case "destroy": 56 return requestDestroy(pw); 57 case "reset": 58 return requestReset(); 59 case "get": 60 return requestGet(pw); 61 case "set": 62 return requestSet(pw); 63 default: 64 return handleDefaultCommands(cmd); 65 } 66 } 67 68 @Override onHelp()69 public void onHelp() { 70 try (final PrintWriter pw = getOutPrintWriter();) { 71 pw.println("AutoFill Service (autofill) commands:"); 72 pw.println(" help"); 73 pw.println(" Prints this help text."); 74 pw.println(""); 75 pw.println(" get log_level "); 76 pw.println(" Gets the Autofill log level (off | debug | verbose)."); 77 pw.println(""); 78 pw.println(" get max_partitions"); 79 pw.println(" Gets the maximum number of partitions per session."); 80 pw.println(""); 81 pw.println(" get max_visible_datasets"); 82 pw.println(" Gets the maximum number of visible datasets in the UI."); 83 pw.println(""); 84 pw.println(" get full_screen_mode"); 85 pw.println(" Gets the Fill UI full screen mode"); 86 pw.println(""); 87 pw.println(" get fc_score [--algorithm ALGORITHM] value1 value2"); 88 pw.println(" Gets the field classification score for 2 fields."); 89 pw.println(""); 90 pw.println(" get bind-instant-service-allowed"); 91 pw.println(" Gets whether binding to services provided by instant apps is allowed"); 92 pw.println(""); 93 pw.println(" get saved-password-count"); 94 pw.println(" Gets the number of saved passwords in the current service."); 95 pw.println(""); 96 pw.println(" set log_level [off | debug | verbose]"); 97 pw.println(" Sets the Autofill log level."); 98 pw.println(""); 99 pw.println(" set max_partitions number"); 100 pw.println(" Sets the maximum number of partitions per session."); 101 pw.println(""); 102 pw.println(" set max_visible_datasets number"); 103 pw.println(" Sets the maximum number of visible datasets in the UI."); 104 pw.println(""); 105 pw.println(" set full_screen_mode [true | false | default]"); 106 pw.println(" Sets the Fill UI full screen mode"); 107 pw.println(""); 108 pw.println(" set bind-instant-service-allowed [true | false]"); 109 pw.println(" Sets whether binding to services provided by instant apps is allowed"); 110 pw.println(""); 111 pw.println(" set temporary-augmented-service USER_ID [COMPONENT_NAME DURATION]"); 112 pw.println(" Temporarily (for DURATION ms) changes the augmented autofill service " 113 + "implementation."); 114 pw.println(" To reset, call with just the USER_ID argument."); 115 pw.println(""); 116 pw.println(" set default-augmented-service-enabled USER_ID [true|false]"); 117 pw.println(" Enable / disable the default augmented autofill service for the user."); 118 pw.println(""); 119 pw.println(" set temporary-detection-service USER_ID [COMPONENT_NAME DURATION]"); 120 pw.println(" Temporarily (for DURATION ms) changes the autofill detection service " 121 + "implementation."); 122 pw.println(" To reset, call with [COMPONENT_NAME 0]."); 123 pw.println(""); 124 pw.println(" get default-augmented-service-enabled USER_ID"); 125 pw.println(" Checks whether the default augmented autofill service is enabled for " 126 + "the user."); 127 pw.println(""); 128 pw.println(" list sessions [--user USER_ID]"); 129 pw.println(" Lists all pending sessions."); 130 pw.println(""); 131 pw.println(" destroy sessions [--user USER_ID]"); 132 pw.println(" Destroys all pending sessions."); 133 pw.println(""); 134 pw.println(" reset"); 135 pw.println(" Resets all pending sessions and cached service connections."); 136 pw.println(""); 137 } 138 } 139 requestGet(PrintWriter pw)140 private int requestGet(PrintWriter pw) { 141 final String what = getNextArgRequired(); 142 switch(what) { 143 case "log_level": 144 return getLogLevel(pw); 145 case "max_partitions": 146 return getMaxPartitions(pw); 147 case "max_visible_datasets": 148 return getMaxVisibileDatasets(pw); 149 case "fc_score": 150 return getFieldClassificationScore(pw); 151 case "full_screen_mode": 152 return getFullScreenMode(pw); 153 case "bind-instant-service-allowed": 154 return getBindInstantService(pw); 155 case "default-augmented-service-enabled": 156 return getDefaultAugmentedServiceEnabled(pw); 157 case "field-detection-service-enabled": 158 return isFieldDetectionServiceEnabled(pw); 159 case "saved-password-count": 160 return getSavedPasswordCount(pw); 161 default: 162 pw.println("Invalid set: " + what); 163 return -1; 164 } 165 } 166 requestSet(PrintWriter pw)167 private int requestSet(PrintWriter pw) { 168 final String what = getNextArgRequired(); 169 170 switch(what) { 171 case "log_level": 172 return setLogLevel(pw); 173 case "max_partitions": 174 return setMaxPartitions(); 175 case "max_visible_datasets": 176 return setMaxVisibileDatasets(); 177 case "full_screen_mode": 178 return setFullScreenMode(pw); 179 case "bind-instant-service-allowed": 180 return setBindInstantService(pw); 181 case "temporary-augmented-service": 182 return setTemporaryAugmentedService(pw); 183 case "default-augmented-service-enabled": 184 return setDefaultAugmentedServiceEnabled(pw); 185 case "temporary-detection-service": 186 return setTemporaryDetectionService(pw); 187 default: 188 pw.println("Invalid set: " + what); 189 return -1; 190 } 191 } 192 getLogLevel(PrintWriter pw)193 private int getLogLevel(PrintWriter pw) { 194 final int logLevel = mService.getLogLevel(); 195 switch (logLevel) { 196 case AutofillManager.FLAG_ADD_CLIENT_VERBOSE: 197 pw.println("verbose"); 198 return 0; 199 case AutofillManager.FLAG_ADD_CLIENT_DEBUG: 200 pw.println("debug"); 201 return 0; 202 case 0: 203 pw.println("off"); 204 return 0; 205 default: 206 pw.println("unknow (" + logLevel + ")"); 207 return 0; 208 } 209 } 210 setLogLevel(PrintWriter pw)211 private int setLogLevel(PrintWriter pw) { 212 final String logLevel = getNextArgRequired(); 213 switch (logLevel.toLowerCase()) { 214 case "verbose": 215 mService.setLogLevel(AutofillManager.FLAG_ADD_CLIENT_VERBOSE); 216 return 0; 217 case "debug": 218 mService.setLogLevel(AutofillManager.FLAG_ADD_CLIENT_DEBUG); 219 return 0; 220 case "off": 221 mService.setLogLevel(AutofillManager.NO_LOGGING); 222 return 0; 223 default: 224 pw.println("Invalid level: " + logLevel); 225 return -1; 226 } 227 } 228 getMaxPartitions(PrintWriter pw)229 private int getMaxPartitions(PrintWriter pw) { 230 pw.println(mService.getMaxPartitions()); 231 return 0; 232 } 233 setMaxPartitions()234 private int setMaxPartitions() { 235 mService.setMaxPartitions(Integer.parseInt(getNextArgRequired())); 236 return 0; 237 } 238 getMaxVisibileDatasets(PrintWriter pw)239 private int getMaxVisibileDatasets(PrintWriter pw) { 240 pw.println(mService.getMaxVisibleDatasets()); 241 return 0; 242 } 243 setMaxVisibileDatasets()244 private int setMaxVisibileDatasets() { 245 mService.setMaxVisibleDatasets(Integer.parseInt(getNextArgRequired())); 246 return 0; 247 } 248 getFieldClassificationScore(PrintWriter pw)249 private int getFieldClassificationScore(PrintWriter pw) { 250 final String nextArg = getNextArgRequired(); 251 final String algorithm, value1; 252 if ("--algorithm".equals(nextArg)) { 253 algorithm = getNextArgRequired(); 254 value1 = getNextArgRequired(); 255 } else { 256 algorithm = null; 257 value1 = nextArg; 258 } 259 final String value2 = getNextArgRequired(); 260 261 final CountDownLatch latch = new CountDownLatch(1); 262 mService.calculateScore(algorithm, value1, value2, new RemoteCallback((result) -> { 263 final Scores scores = result.getParcelable(EXTRA_SCORES, android.service.autofill.AutofillFieldClassificationService.Scores.class); 264 if (scores == null) { 265 pw.println("no score"); 266 } else { 267 pw.println(scores.scores[0][0]); 268 } 269 latch.countDown(); 270 })); 271 272 return waitForLatch(pw, latch); 273 } 274 getFullScreenMode(PrintWriter pw)275 private int getFullScreenMode(PrintWriter pw) { 276 final Boolean mode = mService.getFullScreenMode(); 277 if (mode == null) { 278 pw.println("default"); 279 } else if (mode) { 280 pw.println("true"); 281 } else { 282 pw.println("false"); 283 } 284 return 0; 285 } 286 setFullScreenMode(PrintWriter pw)287 private int setFullScreenMode(PrintWriter pw) { 288 final String mode = getNextArgRequired(); 289 switch (mode.toLowerCase()) { 290 case "true": 291 mService.setFullScreenMode(Boolean.TRUE); 292 return 0; 293 case "false": 294 mService.setFullScreenMode(Boolean.FALSE); 295 return 0; 296 case "default": 297 mService.setFullScreenMode(null); 298 return 0; 299 default: 300 pw.println("Invalid mode: " + mode); 301 return -1; 302 } 303 } 304 getBindInstantService(PrintWriter pw)305 private int getBindInstantService(PrintWriter pw) { 306 if (mService.getAllowInstantService()) { 307 pw.println("true"); 308 } else { 309 pw.println("false"); 310 } 311 return 0; 312 } 313 setBindInstantService(PrintWriter pw)314 private int setBindInstantService(PrintWriter pw) { 315 final String mode = getNextArgRequired(); 316 switch (mode.toLowerCase()) { 317 case "true": 318 mService.setAllowInstantService(true); 319 return 0; 320 case "false": 321 mService.setAllowInstantService(false); 322 return 0; 323 default: 324 pw.println("Invalid mode: " + mode); 325 return -1; 326 } 327 } 328 setTemporaryDetectionService(PrintWriter pw)329 private int setTemporaryDetectionService(PrintWriter pw) { 330 final int userId = getNextIntArgRequired(); 331 final String serviceName = getNextArg(); 332 if (serviceName == null) { 333 mService.resetTemporaryDetectionService(userId); 334 return 0; 335 } 336 final int duration = getNextIntArgRequired(); 337 if (duration <= 0) { 338 mService.resetTemporaryDetectionService(userId); 339 return 0; 340 } 341 342 mService.setTemporaryDetectionService(userId, serviceName, duration); 343 pw.println("Autofill Detection Service temporarily set to " + serviceName + " for " 344 + duration + "ms"); 345 return 0; 346 } 347 isFieldDetectionServiceEnabled(PrintWriter pw)348 private int isFieldDetectionServiceEnabled(PrintWriter pw) { 349 final int userId = getNextIntArgRequired(); 350 boolean enabled = mService.isFieldDetectionServiceEnabledForUser(userId); 351 pw.println(enabled); 352 return 0; 353 } 354 setTemporaryAugmentedService(PrintWriter pw)355 private int setTemporaryAugmentedService(PrintWriter pw) { 356 final int userId = getNextIntArgRequired(); 357 final String serviceName = getNextArg(); 358 if (serviceName == null) { 359 mService.resetTemporaryAugmentedAutofillService(userId); 360 return 0; 361 } 362 final int duration = getNextIntArgRequired(); 363 mService.setTemporaryAugmentedAutofillService(userId, serviceName, duration); 364 pw.println("AugmentedAutofillService temporarily set to " + serviceName + " for " 365 + duration + "ms"); 366 return 0; 367 } 368 getDefaultAugmentedServiceEnabled(PrintWriter pw)369 private int getDefaultAugmentedServiceEnabled(PrintWriter pw) { 370 final int userId = getNextIntArgRequired(); 371 final boolean enabled = mService.isDefaultAugmentedServiceEnabled(userId); 372 pw.println(enabled); 373 return 0; 374 } 375 setDefaultAugmentedServiceEnabled(PrintWriter pw)376 private int setDefaultAugmentedServiceEnabled(PrintWriter pw) { 377 final int userId = getNextIntArgRequired(); 378 final boolean enabled = Boolean.parseBoolean(getNextArgRequired()); 379 final boolean changed = mService.setDefaultAugmentedServiceEnabled(userId, enabled); 380 if (!changed) { 381 pw.println("already " + enabled); 382 } 383 return 0; 384 } 385 getSavedPasswordCount(PrintWriter pw)386 private int getSavedPasswordCount(PrintWriter pw) { 387 final int userId = getNextIntArgRequired(); 388 CountDownLatch latch = new CountDownLatch(1); 389 IResultReceiver resultReceiver = new IResultReceiver.Stub() { 390 @Override 391 public void send(int resultCode, Bundle resultData) { 392 pw.println("resultCode=" + resultCode); 393 if (resultCode == 0 && resultData != null) { 394 pw.println("value=" + resultData.getInt(EXTRA_RESULT)); 395 } 396 latch.countDown(); 397 } 398 }; 399 if (mService.requestSavedPasswordCount(userId, resultReceiver)) { 400 waitForLatch(pw, latch); 401 } 402 return 0; 403 } 404 requestDestroy(PrintWriter pw)405 private int requestDestroy(PrintWriter pw) { 406 if (!isNextArgSessions(pw)) { 407 return -1; 408 } 409 410 final int userId = getUserIdFromArgsOrAllUsers(); 411 final CountDownLatch latch = new CountDownLatch(1); 412 final IResultReceiver receiver = new IResultReceiver.Stub() { 413 @Override 414 public void send(int resultCode, Bundle resultData) { 415 latch.countDown(); 416 } 417 }; 418 return requestSessionCommon(pw, latch, () -> mService.removeAllSessions(userId, receiver)); 419 } 420 requestList(PrintWriter pw)421 private int requestList(PrintWriter pw) { 422 if (!isNextArgSessions(pw)) { 423 return -1; 424 } 425 426 final int userId = getUserIdFromArgsOrAllUsers(); 427 final CountDownLatch latch = new CountDownLatch(1); 428 final IResultReceiver receiver = new IResultReceiver.Stub() { 429 @Override 430 public void send(int resultCode, Bundle resultData) { 431 final ArrayList<String> sessions = resultData 432 .getStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS); 433 for (String session : sessions) { 434 pw.println(session); 435 } 436 latch.countDown(); 437 } 438 }; 439 return requestSessionCommon(pw, latch, () -> mService.listSessions(userId, receiver)); 440 } 441 isNextArgSessions(PrintWriter pw)442 private boolean isNextArgSessions(PrintWriter pw) { 443 final String type = getNextArgRequired(); 444 if (!type.equals("sessions")) { 445 pw.println("Error: invalid list type"); 446 return false; 447 } 448 return true; 449 } 450 requestSessionCommon(PrintWriter pw, CountDownLatch latch, Runnable command)451 private int requestSessionCommon(PrintWriter pw, CountDownLatch latch, 452 Runnable command) { 453 command.run(); 454 return waitForLatch(pw, latch); 455 } 456 waitForLatch(PrintWriter pw, CountDownLatch latch)457 private int waitForLatch(PrintWriter pw, CountDownLatch latch) { 458 try { 459 final boolean received = latch.await(5, TimeUnit.SECONDS); 460 if (!received) { 461 pw.println("Timed out after 5 seconds"); 462 return -1; 463 } 464 } catch (InterruptedException e) { 465 pw.println("System call interrupted"); 466 Thread.currentThread().interrupt(); 467 return -1; 468 } 469 return 0; 470 } 471 requestReset()472 private int requestReset() { 473 mService.reset(); 474 return 0; 475 } 476 getUserIdFromArgsOrAllUsers()477 private int getUserIdFromArgsOrAllUsers() { 478 if ("--user".equals(getNextArg())) { 479 return UserHandle.parseUserArg(getNextArgRequired()); 480 } 481 return UserHandle.USER_ALL; 482 } 483 getNextIntArgRequired()484 private int getNextIntArgRequired() { 485 return Integer.parseInt(getNextArgRequired()); 486 } 487 } 488