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.job; 18 19 import android.Manifest; 20 import android.annotation.Nullable; 21 import android.app.ActivityManager; 22 import android.app.AppGlobals; 23 import android.app.job.JobParameters; 24 import android.content.pm.IPackageManager; 25 import android.content.pm.PackageManager; 26 import android.os.Binder; 27 import android.os.UserHandle; 28 29 import com.android.modules.utils.BasicShellCommandHandler; 30 import com.android.server.job.controllers.JobStatus; 31 32 import java.io.PrintWriter; 33 34 public final class JobSchedulerShellCommand extends BasicShellCommandHandler { 35 public static final int CMD_ERR_NO_PACKAGE = -1000; 36 public static final int CMD_ERR_NO_JOB = -1001; 37 public static final int CMD_ERR_CONSTRAINTS = -1002; 38 39 static final int BYTE_OPTION_DOWNLOAD = 0; 40 static final int BYTE_OPTION_UPLOAD = 1; 41 42 JobSchedulerService mInternal; 43 IPackageManager mPM; 44 JobSchedulerShellCommand(JobSchedulerService service)45 JobSchedulerShellCommand(JobSchedulerService service) { 46 mInternal = service; 47 mPM = AppGlobals.getPackageManager(); 48 } 49 50 @Override onCommand(String cmd)51 public int onCommand(String cmd) { 52 final PrintWriter pw = getOutPrintWriter(); 53 try { 54 switch (cmd != null ? cmd : "") { 55 case "run": 56 return runJob(pw); 57 case "timeout": 58 return timeout(pw); 59 case "cancel": 60 return cancelJob(pw); 61 case "monitor-battery": 62 return monitorBattery(pw); 63 case "disable-flex-policy": 64 return disableFlexPolicy(pw); 65 case "enable-flex-policy": 66 return enableFlexPolicy(pw); 67 case "get-aconfig-flag-state": 68 return getAconfigFlagState(pw); 69 case "get-battery-seq": 70 return getBatterySeq(pw); 71 case "get-battery-charging": 72 return getBatteryCharging(pw); 73 case "get-battery-not-low": 74 return getBatteryNotLow(pw); 75 case "get-config-value": 76 return getConfigValue(pw); 77 case "get-estimated-download-bytes": 78 return getEstimatedNetworkBytes(pw, BYTE_OPTION_DOWNLOAD); 79 case "get-estimated-upload-bytes": 80 return getEstimatedNetworkBytes(pw, BYTE_OPTION_UPLOAD); 81 case "get-storage-seq": 82 return getStorageSeq(pw); 83 case "get-storage-not-low": 84 return getStorageNotLow(pw); 85 case "get-transferred-download-bytes": 86 return getTransferredNetworkBytes(pw, BYTE_OPTION_DOWNLOAD); 87 case "get-transferred-upload-bytes": 88 return getTransferredNetworkBytes(pw, BYTE_OPTION_UPLOAD); 89 case "get-job-state": 90 return getJobState(pw); 91 case "heartbeat": 92 return doHeartbeat(pw); 93 case "cache-config-changes": 94 return cacheConfigChanges(pw); 95 case "reset-execution-quota": 96 return resetExecutionQuota(pw); 97 case "reset-schedule-quota": 98 return resetScheduleQuota(pw); 99 case "reset-flex-policy": 100 return resetFlexPolicy(pw); 101 case "stop": 102 return stop(pw); 103 case "trigger-dock-state": 104 return triggerDockState(pw); 105 default: 106 return handleDefaultCommands(cmd); 107 } 108 } catch (Exception e) { 109 pw.println("Exception: " + e); 110 } 111 return -1; 112 } 113 checkPermission(String operation)114 private void checkPermission(String operation) throws Exception { 115 checkPermission(operation, Manifest.permission.CHANGE_APP_IDLE_STATE); 116 } 117 checkPermission(String operation, String permission)118 private void checkPermission(String operation, String permission) throws Exception { 119 final int uid = Binder.getCallingUid(); 120 if (uid == 0) { 121 // Root can do anything. 122 return; 123 } 124 final int perm = mPM.checkUidPermission(permission, uid); 125 if (perm != PackageManager.PERMISSION_GRANTED) { 126 throw new SecurityException("Uid " + uid 127 + " not permitted to " + operation); 128 } 129 } 130 printError(int errCode, String pkgName, int userId, @Nullable String namespace, int jobId)131 private boolean printError(int errCode, String pkgName, int userId, @Nullable String namespace, 132 int jobId) { 133 PrintWriter pw; 134 switch (errCode) { 135 case CMD_ERR_NO_PACKAGE: 136 pw = getErrPrintWriter(); 137 pw.print("Package not found: "); 138 pw.print(pkgName); 139 pw.print(" / user "); 140 pw.println(userId); 141 return true; 142 143 case CMD_ERR_NO_JOB: 144 pw = getErrPrintWriter(); 145 pw.print("Could not find job "); 146 pw.print(jobId); 147 pw.print(" in package "); 148 pw.print(pkgName); 149 if (namespace != null) { 150 pw.print(" / namespace "); 151 pw.print(namespace); 152 } 153 pw.print(" / user "); 154 pw.println(userId); 155 return true; 156 157 case CMD_ERR_CONSTRAINTS: 158 pw = getErrPrintWriter(); 159 pw.print("Job "); 160 pw.print(jobId); 161 pw.print(" in package "); 162 pw.print(pkgName); 163 if (namespace != null) { 164 pw.print(" / namespace "); 165 pw.print(namespace); 166 } 167 pw.print(" / user "); 168 pw.print(userId); 169 pw.println(" has functional constraints but --force not specified"); 170 return true; 171 172 default: 173 return false; 174 } 175 } 176 runJob(PrintWriter pw)177 private int runJob(PrintWriter pw) throws Exception { 178 checkPermission("force scheduled jobs"); 179 180 boolean force = false; 181 boolean satisfied = false; 182 int userId = UserHandle.USER_SYSTEM; 183 String namespace = null; 184 185 String opt; 186 while ((opt = getNextOption()) != null) { 187 switch (opt) { 188 case "-f": 189 case "--force": 190 force = true; 191 break; 192 193 case "-s": 194 case "--satisfied": 195 satisfied = true; 196 break; 197 198 case "-u": 199 case "--user": 200 userId = UserHandle.parseUserArg(getNextArgRequired()); 201 break; 202 203 case "-n": 204 case "--namespace": 205 namespace = getNextArgRequired(); 206 break; 207 208 default: 209 pw.println("Error: unknown option '" + opt + "'"); 210 return -1; 211 } 212 } 213 214 if (force && satisfied) { 215 pw.println("Cannot specify both --force and --satisfied"); 216 return -1; 217 } 218 219 if (userId == UserHandle.USER_CURRENT) { 220 userId = ActivityManager.getCurrentUser(); 221 } 222 223 final String pkgName = getNextArgRequired(); 224 final int jobId = Integer.parseInt(getNextArgRequired()); 225 226 final long ident = Binder.clearCallingIdentity(); 227 try { 228 int ret = mInternal.executeRunCommand(pkgName, userId, namespace, 229 jobId, satisfied, force); 230 if (printError(ret, pkgName, userId, namespace, jobId)) { 231 return ret; 232 } 233 234 // success! 235 pw.print("Running job"); 236 if (force) { 237 pw.print(" [FORCED]"); 238 } 239 pw.println(); 240 241 return ret; 242 } finally { 243 Binder.restoreCallingIdentity(ident); 244 } 245 } 246 timeout(PrintWriter pw)247 private int timeout(PrintWriter pw) throws Exception { 248 checkPermission("force timeout jobs"); 249 250 int userId = UserHandle.USER_ALL; 251 String namespace = null; 252 253 String opt; 254 while ((opt = getNextOption()) != null) { 255 switch (opt) { 256 case "-u": 257 case "--user": 258 userId = UserHandle.parseUserArg(getNextArgRequired()); 259 break; 260 261 case "-n": 262 case "--namespace": 263 namespace = getNextArgRequired(); 264 break; 265 266 default: 267 pw.println("Error: unknown option '" + opt + "'"); 268 return -1; 269 } 270 } 271 272 if (userId == UserHandle.USER_CURRENT) { 273 userId = ActivityManager.getCurrentUser(); 274 } 275 276 final String pkgName = getNextArg(); 277 final String jobIdStr = getNextArg(); 278 final int jobId = jobIdStr != null ? Integer.parseInt(jobIdStr) : -1; 279 280 final long ident = Binder.clearCallingIdentity(); 281 try { 282 return mInternal.executeStopCommand(pw, pkgName, userId, namespace, 283 jobIdStr != null, jobId, 284 JobParameters.STOP_REASON_TIMEOUT, JobParameters.INTERNAL_STOP_REASON_TIMEOUT); 285 } finally { 286 Binder.restoreCallingIdentity(ident); 287 } 288 } 289 cancelJob(PrintWriter pw)290 private int cancelJob(PrintWriter pw) throws Exception { 291 checkPermission("cancel jobs"); 292 293 int userId = UserHandle.USER_SYSTEM; 294 String namespace = null; 295 296 String opt; 297 while ((opt = getNextOption()) != null) { 298 switch (opt) { 299 case "-u": 300 case "--user": 301 userId = UserHandle.parseUserArg(getNextArgRequired()); 302 break; 303 304 case "-n": 305 case "--namespace": 306 namespace = getNextArgRequired(); 307 break; 308 309 default: 310 pw.println("Error: unknown option '" + opt + "'"); 311 return -1; 312 } 313 } 314 315 if (userId < 0) { 316 pw.println("Error: must specify a concrete user ID"); 317 return -1; 318 } 319 320 final String pkgName = getNextArg(); 321 final String jobIdStr = getNextArg(); 322 final int jobId = jobIdStr != null ? Integer.parseInt(jobIdStr) : -1; 323 324 final long ident = Binder.clearCallingIdentity(); 325 try { 326 return mInternal.executeCancelCommand(pw, pkgName, userId, namespace, 327 jobIdStr != null, jobId); 328 } finally { 329 Binder.restoreCallingIdentity(ident); 330 } 331 } 332 monitorBattery(PrintWriter pw)333 private int monitorBattery(PrintWriter pw) throws Exception { 334 checkPermission("change battery monitoring"); 335 String opt = getNextArgRequired(); 336 boolean enabled; 337 if ("on".equals(opt)) { 338 enabled = true; 339 } else if ("off".equals(opt)) { 340 enabled = false; 341 } else { 342 getErrPrintWriter().println("Error: unknown option " + opt); 343 return 1; 344 } 345 final long ident = Binder.clearCallingIdentity(); 346 try { 347 mInternal.setMonitorBattery(enabled); 348 if (enabled) pw.println("Battery monitoring enabled"); 349 else pw.println("Battery monitoring disabled"); 350 } finally { 351 Binder.restoreCallingIdentity(ident); 352 } 353 return 0; 354 } 355 disableFlexPolicy(PrintWriter pw)356 private int disableFlexPolicy(PrintWriter pw) throws Exception { 357 checkPermission("disable flex policy"); 358 359 final long ident = Binder.clearCallingIdentity(); 360 try { 361 mInternal.setFlexPolicy(true, 0); 362 pw.println("Set flex policy to 0"); 363 return 0; 364 } finally { 365 Binder.restoreCallingIdentity(ident); 366 } 367 } 368 enableFlexPolicy(PrintWriter pw)369 private int enableFlexPolicy(PrintWriter pw) throws Exception { 370 checkPermission("enable flex policy"); 371 372 int enabled = 0; 373 374 String opt; 375 while ((opt = getNextOption()) != null) { 376 switch (opt) { 377 case "-o": 378 case "--option": 379 final String constraint = getNextArgRequired(); 380 switch (constraint) { 381 case "battery-not-low": 382 enabled |= JobStatus.CONSTRAINT_BATTERY_NOT_LOW; 383 break; 384 case "charging": 385 enabled |= JobStatus.CONSTRAINT_CHARGING; 386 break; 387 case "connectivity": 388 enabled |= JobStatus.CONSTRAINT_CONNECTIVITY; 389 break; 390 case "idle": 391 enabled |= JobStatus.CONSTRAINT_IDLE; 392 break; 393 default: 394 pw.println("Unsupported option: " + constraint); 395 return -1; 396 } 397 break; 398 399 default: 400 pw.println("Error: unknown option '" + opt + "'"); 401 return -1; 402 } 403 } 404 405 final long ident = Binder.clearCallingIdentity(); 406 try { 407 mInternal.setFlexPolicy(true, enabled); 408 pw.println("Set flex policy to " + enabled); 409 return 0; 410 } finally { 411 Binder.restoreCallingIdentity(ident); 412 } 413 } 414 getAconfigFlagState(PrintWriter pw)415 private int getAconfigFlagState(PrintWriter pw) throws Exception { 416 checkPermission("get aconfig flag state", Manifest.permission.DUMP); 417 418 final String flagName = getNextArgRequired(); 419 420 switch (flagName) { 421 case android.app.job.Flags.FLAG_ENFORCE_MINIMUM_TIME_WINDOWS: 422 pw.println(android.app.job.Flags.enforceMinimumTimeWindows()); 423 break; 424 case android.app.job.Flags.FLAG_JOB_DEBUG_INFO_APIS: 425 pw.println(android.app.job.Flags.jobDebugInfoApis()); 426 break; 427 case com.android.server.job.Flags.FLAG_BATCH_ACTIVE_BUCKET_JOBS: 428 pw.println(com.android.server.job.Flags.batchActiveBucketJobs()); 429 break; 430 case com.android.server.job.Flags.FLAG_BATCH_CONNECTIVITY_JOBS_PER_NETWORK: 431 pw.println(com.android.server.job.Flags.batchConnectivityJobsPerNetwork()); 432 break; 433 case com.android.server.job.Flags.FLAG_DO_NOT_FORCE_RUSH_EXECUTION_AT_BOOT: 434 pw.println(com.android.server.job.Flags.doNotForceRushExecutionAtBoot()); 435 break; 436 case android.app.job.Flags.FLAG_BACKUP_JOBS_EXEMPTION: 437 pw.println(android.app.job.Flags.backupJobsExemption()); 438 break; 439 default: 440 pw.println("Unknown flag: " + flagName); 441 break; 442 } 443 return 0; 444 } 445 getBatterySeq(PrintWriter pw)446 private int getBatterySeq(PrintWriter pw) { 447 int seq = mInternal.getBatterySeq(); 448 pw.println(seq); 449 return 0; 450 } 451 getBatteryCharging(PrintWriter pw)452 private int getBatteryCharging(PrintWriter pw) { 453 boolean val = mInternal.isBatteryCharging(); 454 pw.println(val); 455 return 0; 456 } 457 getBatteryNotLow(PrintWriter pw)458 private int getBatteryNotLow(PrintWriter pw) { 459 boolean val = mInternal.isBatteryNotLow(); 460 pw.println(val); 461 return 0; 462 } 463 getConfigValue(PrintWriter pw)464 private int getConfigValue(PrintWriter pw) throws Exception { 465 checkPermission("get device config value", Manifest.permission.DUMP); 466 467 final String key = getNextArgRequired(); 468 469 final long ident = Binder.clearCallingIdentity(); 470 try { 471 pw.println(mInternal.getConfigValue(key)); 472 return 0; 473 } finally { 474 Binder.restoreCallingIdentity(ident); 475 } 476 } 477 getEstimatedNetworkBytes(PrintWriter pw, int byteOption)478 private int getEstimatedNetworkBytes(PrintWriter pw, int byteOption) throws Exception { 479 checkPermission("get estimated bytes"); 480 481 int userId = UserHandle.USER_SYSTEM; 482 String namespace = null; 483 484 String opt; 485 while ((opt = getNextOption()) != null) { 486 switch (opt) { 487 case "-u": 488 case "--user": 489 userId = UserHandle.parseUserArg(getNextArgRequired()); 490 break; 491 492 case "-n": 493 case "--namespace": 494 namespace = getNextArgRequired(); 495 break; 496 497 default: 498 pw.println("Error: unknown option '" + opt + "'"); 499 return -1; 500 } 501 } 502 503 if (userId == UserHandle.USER_CURRENT) { 504 userId = ActivityManager.getCurrentUser(); 505 } 506 507 final String pkgName = getNextArgRequired(); 508 final String jobIdStr = getNextArgRequired(); 509 final int jobId = Integer.parseInt(jobIdStr); 510 511 final long ident = Binder.clearCallingIdentity(); 512 try { 513 int ret = mInternal.getEstimatedNetworkBytes(pw, pkgName, userId, namespace, 514 jobId, byteOption); 515 printError(ret, pkgName, userId, namespace, jobId); 516 return ret; 517 } finally { 518 Binder.restoreCallingIdentity(ident); 519 } 520 } 521 getStorageSeq(PrintWriter pw)522 private int getStorageSeq(PrintWriter pw) { 523 int seq = mInternal.getStorageSeq(); 524 pw.println(seq); 525 return 0; 526 } 527 getStorageNotLow(PrintWriter pw)528 private int getStorageNotLow(PrintWriter pw) { 529 boolean val = mInternal.getStorageNotLow(); 530 pw.println(val); 531 return 0; 532 } 533 getTransferredNetworkBytes(PrintWriter pw, int byteOption)534 private int getTransferredNetworkBytes(PrintWriter pw, int byteOption) throws Exception { 535 checkPermission("get transferred bytes"); 536 537 int userId = UserHandle.USER_SYSTEM; 538 String namespace = null; 539 540 String opt; 541 while ((opt = getNextOption()) != null) { 542 switch (opt) { 543 case "-u": 544 case "--user": 545 userId = UserHandle.parseUserArg(getNextArgRequired()); 546 break; 547 548 case "-n": 549 case "--namespace": 550 namespace = getNextArgRequired(); 551 break; 552 553 default: 554 pw.println("Error: unknown option '" + opt + "'"); 555 return -1; 556 } 557 } 558 559 if (userId == UserHandle.USER_CURRENT) { 560 userId = ActivityManager.getCurrentUser(); 561 } 562 563 final String pkgName = getNextArgRequired(); 564 final String jobIdStr = getNextArgRequired(); 565 final int jobId = Integer.parseInt(jobIdStr); 566 567 final long ident = Binder.clearCallingIdentity(); 568 try { 569 int ret = mInternal.getTransferredNetworkBytes(pw, pkgName, userId, namespace, 570 jobId, byteOption); 571 printError(ret, pkgName, userId, namespace, jobId); 572 return ret; 573 } finally { 574 Binder.restoreCallingIdentity(ident); 575 } 576 } 577 getJobState(PrintWriter pw)578 private int getJobState(PrintWriter pw) throws Exception { 579 checkPermission("get job state"); 580 581 int userId = UserHandle.USER_SYSTEM; 582 String namespace = null; 583 584 String opt; 585 while ((opt = getNextOption()) != null) { 586 switch (opt) { 587 case "-u": 588 case "--user": 589 userId = UserHandle.parseUserArg(getNextArgRequired()); 590 break; 591 592 case "-n": 593 case "--namespace": 594 namespace = getNextArgRequired(); 595 break; 596 597 default: 598 pw.println("Error: unknown option '" + opt + "'"); 599 return -1; 600 } 601 } 602 603 if (userId == UserHandle.USER_CURRENT) { 604 userId = ActivityManager.getCurrentUser(); 605 } 606 607 final String pkgName = getNextArgRequired(); 608 final String jobIdStr = getNextArgRequired(); 609 final int jobId = Integer.parseInt(jobIdStr); 610 611 final long ident = Binder.clearCallingIdentity(); 612 try { 613 int ret = mInternal.getJobState(pw, pkgName, userId, namespace, jobId); 614 printError(ret, pkgName, userId, namespace, jobId); 615 return ret; 616 } finally { 617 Binder.restoreCallingIdentity(ident); 618 } 619 } 620 doHeartbeat(PrintWriter pw)621 private int doHeartbeat(PrintWriter pw) throws Exception { 622 checkPermission("manipulate scheduler heartbeat"); 623 624 pw.println("Heartbeat command is no longer supported"); 625 return -1; 626 } 627 cacheConfigChanges(PrintWriter pw)628 private int cacheConfigChanges(PrintWriter pw) throws Exception { 629 checkPermission("change config caching", Manifest.permission.DUMP); 630 String opt = getNextArgRequired(); 631 boolean enabled; 632 if ("on".equals(opt)) { 633 enabled = true; 634 } else if ("off".equals(opt)) { 635 enabled = false; 636 } else { 637 getErrPrintWriter().println("Error: unknown option " + opt); 638 return 1; 639 } 640 final long ident = Binder.clearCallingIdentity(); 641 try { 642 mInternal.setCacheConfigChanges(enabled); 643 pw.println("Config caching " + (enabled ? "enabled" : "disabled")); 644 } finally { 645 Binder.restoreCallingIdentity(ident); 646 } 647 return 0; 648 } 649 resetFlexPolicy(PrintWriter pw)650 private int resetFlexPolicy(PrintWriter pw) throws Exception { 651 checkPermission("reset flex policy"); 652 653 final long ident = Binder.clearCallingIdentity(); 654 try { 655 mInternal.setFlexPolicy(false, 0); 656 pw.println("Reset flex policy to its default state"); 657 return 0; 658 } finally { 659 Binder.restoreCallingIdentity(ident); 660 } 661 } 662 resetExecutionQuota(PrintWriter pw)663 private int resetExecutionQuota(PrintWriter pw) throws Exception { 664 checkPermission("reset execution quota"); 665 666 int userId = UserHandle.USER_SYSTEM; 667 668 String opt; 669 while ((opt = getNextOption()) != null) { 670 switch (opt) { 671 case "-u": 672 case "--user": 673 userId = UserHandle.parseUserArg(getNextArgRequired()); 674 break; 675 676 default: 677 pw.println("Error: unknown option '" + opt + "'"); 678 return -1; 679 } 680 } 681 682 if (userId == UserHandle.USER_CURRENT) { 683 userId = ActivityManager.getCurrentUser(); 684 } 685 686 final String pkgName = getNextArgRequired(); 687 688 final long ident = Binder.clearCallingIdentity(); 689 try { 690 mInternal.resetExecutionQuota(pkgName, userId); 691 } finally { 692 Binder.restoreCallingIdentity(ident); 693 } 694 return 0; 695 } 696 resetScheduleQuota(PrintWriter pw)697 private int resetScheduleQuota(PrintWriter pw) throws Exception { 698 checkPermission("reset schedule quota"); 699 700 final long ident = Binder.clearCallingIdentity(); 701 try { 702 mInternal.resetScheduleQuota(); 703 } finally { 704 Binder.restoreCallingIdentity(ident); 705 } 706 return 0; 707 } 708 stop(PrintWriter pw)709 private int stop(PrintWriter pw) throws Exception { 710 checkPermission("stop jobs"); 711 712 int userId = UserHandle.USER_ALL; 713 String namespace = null; 714 int stopReason = JobParameters.STOP_REASON_USER; 715 int internalStopReason = JobParameters.INTERNAL_STOP_REASON_UNKNOWN; 716 717 String opt; 718 while ((opt = getNextOption()) != null) { 719 switch (opt) { 720 case "-u": 721 case "--user": 722 userId = UserHandle.parseUserArg(getNextArgRequired()); 723 break; 724 725 case "-n": 726 case "--namespace": 727 namespace = getNextArgRequired(); 728 break; 729 730 case "-s": 731 case "--stop-reason": 732 stopReason = Integer.parseInt(getNextArgRequired()); 733 break; 734 735 case "-i": 736 case "--internal-stop-reason": 737 internalStopReason = Integer.parseInt(getNextArgRequired()); 738 break; 739 740 default: 741 pw.println("Error: unknown option '" + opt + "'"); 742 return -1; 743 } 744 } 745 746 if (userId == UserHandle.USER_CURRENT) { 747 userId = ActivityManager.getCurrentUser(); 748 } 749 750 final String pkgName = getNextArg(); 751 final String jobIdStr = getNextArg(); 752 final int jobId = jobIdStr != null ? Integer.parseInt(jobIdStr) : -1; 753 754 final long ident = Binder.clearCallingIdentity(); 755 try { 756 return mInternal.executeStopCommand(pw, pkgName, userId, namespace, 757 jobIdStr != null, jobId, stopReason, internalStopReason); 758 } finally { 759 Binder.restoreCallingIdentity(ident); 760 } 761 } 762 triggerDockState(PrintWriter pw)763 private int triggerDockState(PrintWriter pw) throws Exception { 764 checkPermission("trigger wireless charging dock state"); 765 766 final String opt = getNextArgRequired(); 767 boolean idleState; 768 if ("idle".equals(opt)) { 769 idleState = true; 770 } else if ("active".equals(opt)) { 771 idleState = false; 772 } else { 773 getErrPrintWriter().println("Error: unknown option " + opt); 774 return 1; 775 } 776 777 final long ident = Binder.clearCallingIdentity(); 778 try { 779 mInternal.triggerDockState(idleState); 780 } finally { 781 Binder.restoreCallingIdentity(ident); 782 } 783 return 0; 784 } 785 786 @Override onHelp()787 public void onHelp() { 788 final PrintWriter pw = getOutPrintWriter(); 789 790 pw.println("Job scheduler (jobscheduler) commands:"); 791 pw.println(" help"); 792 pw.println(" Print this help text."); 793 pw.println(" run [-f | --force] [-s | --satisfied] [-u | --user USER_ID]" 794 + " [-n | --namespace NAMESPACE] PACKAGE JOB_ID"); 795 pw.println(" Trigger immediate execution of a specific scheduled job. For historical"); 796 pw.println(" reasons, some constraints, such as battery, are ignored when this"); 797 pw.println(" command is called. If you don't want any constraints to be ignored,"); 798 pw.println(" include the -s flag."); 799 pw.println(" Options:"); 800 pw.println(" -f or --force: run the job even if technical constraints such as"); 801 pw.println(" connectivity are not currently met. This is incompatible with -f "); 802 pw.println(" and so an error will be reported if both are given."); 803 pw.println(" -n or --namespace: specify the namespace this job sits in; the default"); 804 pw.println(" is null (no namespace)."); 805 pw.println(" -s or --satisfied: run the job only if all constraints are met."); 806 pw.println(" This is incompatible with -f and so an error will be reported"); 807 pw.println(" if both are given."); 808 pw.println(" -u or --user: specify which user's job is to be run; the default is"); 809 pw.println(" the primary or system user"); 810 pw.println(" stop [-u | --user USER_ID] [-n | --namespace NAMESPACE]" 811 + " [-s | --stop-reason STOP_REASON] [-i | --internal-stop-reason STOP_REASON]" 812 + " [PACKAGE] [JOB_ID]"); 813 pw.println(" Trigger immediate stop of currently executing jobs using the specified"); 814 pw.println(" stop reasons."); 815 pw.println(" Options:"); 816 pw.println(" -u or --user: specify which user's job is to be run; the default is"); 817 pw.println(" all users"); 818 pw.println(" -n or --namespace: specify the namespace this job sits in; the default"); 819 pw.println(" is null (no namespace)."); 820 pw.println(" -s or --stop-reason: specify the stop reason given to the job."); 821 pw.println(" Valid values are those that can be returned from"); 822 pw.println(" JobParameters.getStopReason()."); 823 pw.println(" The default value is STOP_REASON_USER."); 824 pw.println(" -i or --internal-stop-reason: specify the internal stop reason."); 825 pw.println(" JobScheduler will use for internal processing."); 826 pw.println(" Valid values are those that can be returned from"); 827 pw.println(" JobParameters.getInternalStopReason()."); 828 pw.println(" The default value is INTERNAL_STOP_REASON_UNDEFINED."); 829 pw.println(" timeout [-u | --user USER_ID] [-n | --namespace NAMESPACE]" 830 + " [PACKAGE] [JOB_ID]"); 831 pw.println(" Trigger immediate timeout of currently executing jobs, as if their"); 832 pw.println(" execution timeout had expired."); 833 pw.println(" This is the equivalent of calling `stop -s 3 -i 3`."); 834 pw.println(" Options:"); 835 pw.println(" -u or --user: specify which user's job is to be run; the default is"); 836 pw.println(" all users"); 837 pw.println(" -n or --namespace: specify the namespace this job sits in; the default"); 838 pw.println(" is null (no namespace)."); 839 pw.println(" cancel [-u | --user USER_ID] [-n | --namespace NAMESPACE] PACKAGE [JOB_ID]"); 840 pw.println(" Cancel a scheduled job. If a job ID is not supplied, all jobs scheduled"); 841 pw.println(" by that package will be canceled. USE WITH CAUTION."); 842 pw.println(" Options:"); 843 pw.println(" -u or --user: specify which user's job is to be run; the default is"); 844 pw.println(" the primary or system user"); 845 pw.println(" -n or --namespace: specify the namespace this job sits in; the default"); 846 pw.println(" is null (no namespace)."); 847 pw.println(" heartbeat [num]"); 848 pw.println(" No longer used."); 849 pw.println(" cache-config-changes [on|off]"); 850 pw.println(" Control caching the set of most recently processed config flags."); 851 pw.println(" Off by default. Turning on makes get-config-value useful."); 852 pw.println(" monitor-battery [on|off]"); 853 pw.println(" Control monitoring of all battery changes. Off by default. Turning"); 854 pw.println(" on makes get-battery-seq useful."); 855 pw.println(" enable-flex-policy --option <option>"); 856 pw.println(" Enable flex policy with the specified options. Supported options are"); 857 pw.println(" battery-not-low, charging, connectivity, idle."); 858 pw.println(" Multiple enable options can be specified (e.g."); 859 pw.println(" enable-flex-policy --option battery-not-low --option charging"); 860 pw.println(" disable-flex-policy"); 861 pw.println(" Turn off flex policy so that it does not affect job execution."); 862 pw.println(" reset-flex-policy"); 863 pw.println(" Resets the flex policy to its default state."); 864 pw.println(" get-aconfig-flag-state FULL_FLAG_NAME"); 865 pw.println(" Return the state of the specified aconfig flag, if known. The flag name"); 866 pw.println(" must be fully qualified."); 867 pw.println(" get-battery-seq"); 868 pw.println(" Return the last battery update sequence number that was received."); 869 pw.println(" get-battery-charging"); 870 pw.println(" Return whether the battery is currently considered to be charging."); 871 pw.println(" get-battery-not-low"); 872 pw.println(" Return whether the battery is currently considered to not be low."); 873 pw.println(" get-config-value KEY"); 874 pw.println(" Return the most recently processed and cached config value for the KEY."); 875 pw.println(" Only useful if caching is turned on with cache-config-changes."); 876 pw.println(" get-estimated-download-bytes [-u | --user USER_ID]" 877 + " [-n | --namespace NAMESPACE] PACKAGE JOB_ID"); 878 pw.println(" Return the most recent estimated download bytes for the job."); 879 pw.println(" Options:"); 880 pw.println(" -u or --user: specify which user's job is to be run; the default is"); 881 pw.println(" the primary or system user"); 882 pw.println(" get-estimated-upload-bytes [-u | --user USER_ID]" 883 + " [-n | --namespace NAMESPACE] PACKAGE JOB_ID"); 884 pw.println(" Return the most recent estimated upload bytes for the job."); 885 pw.println(" Options:"); 886 pw.println(" -u or --user: specify which user's job is to be run; the default is"); 887 pw.println(" the primary or system user"); 888 pw.println(" get-storage-seq"); 889 pw.println(" Return the last storage update sequence number that was received."); 890 pw.println(" get-storage-not-low"); 891 pw.println(" Return whether storage is currently considered to not be low."); 892 pw.println(" get-transferred-download-bytes [-u | --user USER_ID]" 893 + " [-n | --namespace NAMESPACE] PACKAGE JOB_ID"); 894 pw.println(" Return the most recent transferred download bytes for the job."); 895 pw.println(" Options:"); 896 pw.println(" -u or --user: specify which user's job is to be run; the default is"); 897 pw.println(" the primary or system user"); 898 pw.println(" get-transferred-upload-bytes [-u | --user USER_ID]" 899 + " [-n | --namespace NAMESPACE] PACKAGE JOB_ID"); 900 pw.println(" Return the most recent transferred upload bytes for the job."); 901 pw.println(" Options:"); 902 pw.println(" -u or --user: specify which user's job is to be run; the default is"); 903 pw.println(" the primary or system user"); 904 pw.println(" get-job-state [-u | --user USER_ID] [-n | --namespace NAMESPACE]" 905 + " PACKAGE JOB_ID"); 906 pw.println(" Return the current state of a job, may be any combination of:"); 907 pw.println(" pending: currently on the pending list, waiting to be active"); 908 pw.println(" active: job is actively running"); 909 pw.println(" user-stopped: job can't run because its user is stopped"); 910 pw.println(" backing-up: job can't run because app is currently backing up its data"); 911 pw.println(" no-component: job can't run because its component is not available"); 912 pw.println(" ready: job is ready to run (all constraints satisfied or bypassed)"); 913 pw.println(" waiting: if nothing else above is printed, job not ready to run"); 914 pw.println(" Options:"); 915 pw.println(" -u or --user: specify which user's job is to be run; the default is"); 916 pw.println(" the primary or system user"); 917 pw.println(" -n or --namespace: specify the namespace this job sits in; the default"); 918 pw.println(" is null (no namespace)."); 919 pw.println(" trigger-dock-state [idle|active]"); 920 pw.println(" Trigger wireless charging dock state. Active by default."); 921 pw.println(); 922 } 923 } 924