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